使用$?在if语句中


12
function foo {
   (cd $FOOBAR;
   <some command>
   if [$? -ne 0]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

我正在尝试编写类似上面的函数,并将其放在我的.bashrc文件中。在获取文件并运行后,我得到:

总时间:51秒-重
击:[1:找不到命令

有人可以帮助我了解我做错了什么吗?


4
$?用一条if语句测试if 是否等于0 是没有意义的,if需要一个命令,如果该命令返回0,它将在块中运行代码。if true; then echo hello; fi因为命令true返回,所以会回声你好0
llua 2014年

1
@llua不是没有意义的。$?保留最后一个管道的状态,该状态不是语句中的test[)命令if。该示例正在测试是否some command成功。您可以使用&&和进行相同的操作||,但是与相比,它可以使行长且难以理解if [ $? -eq 0 ]。同样的观点也适用于if some command
bonsaiviking 2014年

@bonsaiviking我很清楚$?扩展到什么,我指出test被使用毫无意义;因为if some command使用一个语句而不是使用两个单独的语句可以完成相同的操作。如果命令已经很长,再添加三个字符不会使“不可读”变得更加“不可读”。
llua 2014年

Answers:


33

在之后添加一个空格,在[之前添加另一个]

function foo {
   (cd $FOOBAR;
   <some command>
   if [ $? -ne 0 ]
   then
      echo "Nope!"
   else
      echo "OK!"
   fi
   )
}

[是一个内置的shell,它是一个命令,就像,,... 一样echo,它后面需要一个空格,并且需要match 。readexpr]

写作[ $? -ne 0 ]其实就是调用[并给它4个参数:$?-ne0,和]

注意:您得到一个错误说的事实[1: command not found是手段$?是具有重要的价值1


1
我刚刚确认您的答案在我的Linux VM上是正确的。
samiam 2014年

[是一个链接test,以及
瑞奇梁

2
@RickyBeam在大多数shell中[都是内置的shell,/usr/bin/[很少使用。
帕特里克

20

或者,您可以$?完全跳过。如果您的命令是cmd,则以下命令应该起作用:

function foo {
   (cd $FOOBAR;
   if cmd
   then
      echo "OK!"
   else
      echo "Nope!"
   fi
   )
}

6

优良作法是在使用返回值之前将其分配给变量

retval="$?"
if [ $retval -ne 0 ]

它允许您重用返回值。例如在if ... elif ... else ...语句中。


-1:您忘记了空格[(如果没有空格,它将成为中的语法错误bash),如果您编辑并修复错误,则该操作将撤消。
samiam 2014年

是的,你是对的。我修好了它。
阿卜杜勒2014年

@samiam,最后一条评论是针对您的
terdon

4
:)您能否扩大答案。为什么是好的做法?可以避免什么样的错误?
terdon

1
@terdon,$?直接使用是一种不好的做法,因为如果您以后编辑脚本时,在命令和$?检查之间加上一行,这会中断。
samiam 2014年

3

想要$?用作[命令参数(无论该[命令是否在if语句的条件部分中运行)的唯一原因是当您要区分特定的返回状态时,例如:

until
  cmd
  [ "$?" -gt 1 ]
do
  something
done

所有这些语法ifwhileuntil...语句是

if cmd-list1
then cmd-list2
else cmd-list3
fi

cmd-list2如果cmd-list1成功则以哪个方式运行cmd-list3

[ "$?" -eq 0 ]命令是无操作的。$?如果$?为0,则设置为0;如果$?非零,则设置为非零。

如果您想在cmd失败时运行某些程序,则为:

if ! cmd
then ...
fi

通常,您无需费心修改$?哪个值表示truefalse。如果您需要区分特定值,或者需要将其保存以供以后使用(例如,将其作为函数的返回值),则只有上述情况:

f() {
  cmd; ret=$?
  some cleanup
  return "$ret"
}

还请记住,split + glob运算符使变量不加引号。在这里调用该运算符没有任何意义,因此应为:

[ "$?" -ne 0 ]

不是[ $? -ne 0 ],更不用说了[$? -ne 0 ](仅[$IFS碰巧包含的第一个字符时才调用命令$?)。

还要注意,定义函数的Bourne方法是坚持function-name()在命令前面。除bashyash(以及的最新版本posh)仅允许复合命令(复合命令为{...}(...)for...doneif...fi... 等)之外,每个像Bourne这样的shell都是这种情况

function foo { ... }ksh函数定义语法。没有理由要在这里使用它。

您的代码可以移植(POSIXly)编写:

foo() (
  cd -P -- "$FOOBAR" || return # what if the cd failed!
  if
    <some command>
  then
    echo 'OK!'
  else
    echo 'Nope!'
  fi
)

还要注意,cdnot -P具有非常特殊的含义(处理包含..与其他命令不同的组件的路径),因此最好将其包含在脚本中以避免混淆。

(该函数falsecd失败时返回,但在<some command>失败时不返回)。


1

我确实相信下面的命令可以在一行中完成您想要的所有操作。

(( verify = $?!=0?'Nope!':'OK!' ))
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.