如果命令成功或失败,如何有条件地执行某些操作


283

我该如何在bash中做类似的事情?

if "`command` returns any error";
then
    echo "Returned an error"
else
    echo "Proceed..."
fi

Answers:


359

如果命令成功或失败,如何有条件地执行某些操作

这正是bash的if声明所要做的:

if command ; then
    echo "Command succeeded"
else
    echo "Command failed"
fi

从留言中加入信息:您没有需要使用[... ]语法,在这种情况下。[本身就是命令,几乎等同于test。这可能是在中使用的最常见的命令if,这可能导致人们假设它是Shell语法的一部分。但是,如果要测试命令是否成功,请直接使用本身if显示命令,如上所示。

编辑:为了清楚起见,在顶部引用了问题(此答案未出现在页面顶部附近)。


11
请注意,分号很重要。
托尔比约恩Ravn的安徒生

21
或者,您也可以放then一行。
2011年

36
@乔:我想你是说if ! command ; then ... ; fi[本身就是命令,在这种情况下不需要。
基思·汤普森

20
@乔:我的方式还具有正确的优点。 if [ ! command ]不执行command; 它把command作为一个字符串,将其视为正确的,因为它有一个非零的长度。 [test命令的同义词
Keith Thompson

5
哎呀。没错
2012年

133

对于如果shell命令起作用而希望发生的小事情,可以使用以下&&结构:

rm -rf somedir && trace_output "Removed the directory"

同样,对于在shell命令失败时希望发生的小事情,可以使用||

rm -rf somedir || exit_on_error "Failed to remove the directory"

或两者

rm -rf somedir && trace_output "Removed the directory" || exit_on_error "Failed to remove the directory"

对这些结构进行很多工作可能是不明智的,但是有时它们可​​以使控制流程更加清晰。


3
它们更短并且(至少在某些外壳中)更快。我不禁想起一个怪兽Ultrix安装脚本,它只是用我曾经试图破译的这些条件结构编写的……
vonbrand

101

检查的值$?,其中包含执行最新命令/函数的结果:

#!/bin/bash

echo "this will work"
RESULT=$?
if [ $RESULT -eq 0 ]; then
  echo success
else
  echo failed
fi

if [ $RESULT == 0 ]; then
  echo success 2
else
  echo failed 2
fi

11
尽管从技术上讲是正确的(因此不保证投票结果是正确的),但它并没有利用Bash的if习惯用法。我更喜欢基思·汤普森的答案。
janmoesen

16
这个习惯用法有很多好处-它保留了返回值。总的来说,我觉得这个功能更强大,虽然更详细。它也更容易阅读。
出租车司机

2
什么是“ Bash的成语”?
Nowaker

3
@Nowaker的唯一目的if是这样做。Bash中的流控制条件都在$?后台检查;那就是他们的工作在绝大多数情况下,没有必要明确检查其值,并且通常是初学者的反模式。
三胞胎

1
@lunakid如果您不关心退出代码,if ! cmd可以。否则,常见的安排是使用else子句。你不能有一个空的then,但你有时会看到then : nothing; else其中的:任何操作是显著。true也会在那里工作。
三点

47

这为我工作:

command && echo "OK" || echo "NOK"

如果command成功,则echo "OK"执行,并且由于成功,因此在此处停止执行。否则,将&&被跳过并echo "NOK"执行。


5
如果您想在失败时执行某项操作并保留退出代码(以显示在命令提示符下或在脚本中进行测试),则可以执行以下操作: command && echo "OK" || c=$?; echo "NOK"; $(exit $c)
Sam Hasler 2014年

2
@ Sam-Hasler:不是command && echo "OK" || (c=$?; echo "NOK"; (exit $c))吗?
jrw32982

9
另外,如果echo "OK"零件本身可能会失效,那么这会更好:command && (echo "OK"; exit 0) || (c=$?; echo "NOK"; (exit $c))
jrw32982

@ jrw32982,很好,我使用了前一种构造,但没有使用过后者。
山姆·哈斯勒

真正的答案是在评论中,谢谢大家!
Joshua Pinter

6

应该注意的是,if...then...fi&&/ ||方法的类型涉及我们要测试的命令返回的退出状态(成功时为0);但是,如果命令失败或无法处理输入,则某些命令不会返回非零退出状态。这意味着通常的if&&/ ||方法对那些特定命令不起作用。

例如,在Linux上file,如果GNU 接收到不存在的文件作为参数并且find无法找到指定的文件用户,则GNU 仍将以0退出。

$ find . -name "not_existing_file"                                          
$ echo $?
0
$ file ./not_existing_file                                                  
./not_existing_file: cannot open `./not_existing_file' (No such file or directory)
$ echo $?
0

在这种情况下,我们可能会处理这种情况的一种可能方式是读取stderr/ stdin消息,例如,由file命令返回的消息,或解析命令的输出,例如in find。为此,case可以使用语句。

$ file ./doesntexist  | while IFS= read -r output; do                                                                                                                  
> case "$output" in 
> *"No such file or directory"*) printf "%s\n" "This will show up if failed";;
> *) printf "%s\n" "This will show up if succeeded" ;;
> esac
> done
This will show up if failed

$ find . -name "doesn'texist" | if ! read IFS= out; then echo "File not found"; fi                                                                                     
File not found

2

我能想到的最容易出错的是:

  • 首先,获取价值。假设您执行以下操作:

RR=$?

现在,不仅针对这种情况,而且可能面对的其他情况,请考虑:

定义的变量:

$ AA=1 ; if (( "10#0${AA}" == 1 )) ; then echo yes ; else echo no ; fi

答:是的

$ AA=1 ; if (( "10#0${AA}" != 1 )) ; then echo yes ; else echo no ; fi

答:不可以

未定义的变量:

$ AA=1 ; if (( "10#0${BB}" == 1 )) ; then echo yes ; else echo no ; fi

答:不可以

$ AA=1 ; if (( "10#0${BB}" != 1 )) ; then echo yes ; else echo no ; fi

答:是的

$ AA=1 ; if (( "10#0${BB}" == 0 )) ; then echo yes ; else echo no ; fi

答:是的

这样可以防止各种错误。

您可能已经知道所有语法,但是这里有一些提示:

  • 使用引号。避免"blank"成为nothing
  • 变量的新现代记法是${variable}
  • 在您的电话号码前添加一个串联的零也可以避免“根本没有电话号码”。
  • 但是,等等,加一个零会使数字变为base-8。您将收到类似以下的错误:
    • value too great for base (error token is "08")对于以上数字7。那是什么时候10#起作用:
    • 10#强制数字为base-10

1

你可以这样做:

if ($( ping 4.4.4.4 -c1 > /dev/null )) ; then
  echo "ping response succsess!!!"
fi

9
可行,但令人费解。您正在子外壳程序的子外壳程序中运行ping,ping鉴于将其作为命令运行,将捕获的输出。但是因为输出重定向到/ dev / null,所以它将始终是空字符串。因此,您在子Shell中什么也没有运行,这意味着将保留先前的退出状态(命令替换子Shell的状态,即ping)。显然,正确的方法就if ping ...; then在这里。
斯特凡Chazelas

1

如本主题其他地方所述,原始问题基本上可以回答自己。这是说明if条件也可能嵌套的图示。

本示例用于if检查文件是否存在以及是否为常规文件。如果满足这些条件,则检查其大小是否大于0。

#!/bin/bash

echo "Which error log are you checking today? "
read answer

if [ -f /opt/logs/$answer*.errors ]
    then
        if [ -s /opt/logs/$answer*.errors ]
            then
                echo "Content is present in the $answer error log file."
            else
                echo "No errors are present in the $answer error log file."
        fi
    else
        echo "$answer does not have an error log at this time."
fi

2
那就是您的答案所做的,但是您的答案并未解决该问题。
杰夫·谢勒

@JeffSchaller,感谢您的来信。我编辑了帖子,以包括对该问题的引用。
quartzinquartz


-3

这可以简单地通过这种方式完成,因为$?它为您提供了最后执行的命令的状态。

所以可能是

#!/bin/sh

... some command ...

if [ $? == 0 ] ; then
  echo '<the output message you want to display>'
else 
  echo '<failure message>'
fi

1
Downvote:这简单地解释了一个较早的答案,该答案理所当然地受到批评,认为它是单反的。
三人房
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.