Tcsh 脚本上次退出代码 ($?) 值正在重置

Tcsh Script Last Exit Code ($?) value is resetting

我正在 运行使用 tcsh 创建以下脚本。在我的 while 循环中,我正在 运行 宁我创建的 C++ 程序,并将 return 根据某些事情不同的退出代码。虽然它 return 的退出代码为 0,但我希望脚本增加计数器并再次 运行 程序。

#!/bin/tcsh

echo "Starting the script."
set counter = 0

while ($? == 0)
    @ counter ++
    ./auto $counter
end

我已经验证我的程序在某个点后确实 returning 退出代码 = 1。但是,while 循环中的条件由于某种原因一直评估为 true 并且 运行ning.

我发现如果我在循环末尾添加以下行,然后用这个新变量替换 while 循环中的条件检查,它就可以正常工作。

while ($return_code == 0)
    @ counter ++
    ./auto $counter
    set return_code = $?
end

为什么我不能只使用 $?直接地? 运行 在我的自定义程序和检查导致 $ 的循环条件之间是否执行了另一个幕后操作?更改值?

这很奇怪。

我已将您的示例更改为我认为可以更清楚地说明问题的内容。 (注意 $?$status 的别名。)

#!/bin/tcsh -f

foreach i (1 2 3)
    false
    # echo false status=$status
end
echo Done status=$status

输出是

Done status=0

如果我取消注释循环中的 echo 命令,输出为:

false status=1
false status=1
false status=1
Done status=0

(当然,循环中的 echo 无论如何都会破坏逻辑,因为 echo 命令成功完成并将 $status 设置为零。)

认为发生的事情是终止循环的end作为语句执行,它设置$status$?) 到 0.

我看到 tcshbsd-csh 的行为相同。

在命令后立即将 $status 的值保存在另一个变量中是一个很好的解决方法——并且可以说是一种更好的方法,因为 $status 非常脆弱,并且几乎如果你看着它,真的会被破坏。

请注意,我在 #! 行中添加了一个 -f 选项。这可以防止 tcsh 获取您的初始化文件(.cshrc.tcshrc),这被认为是一种很好的做法。 (sh/bash/ksh/zsh 的情况并非如此,它赋予 -f 完全不同的含义。)

题外话:多年来我经常使用 tcsh,既作为我的交互式登录 shell 又用于编写脚本。我不会预料到 end 会设置 $status。这不是我第一次不得不通过反复试验找出 tcshcsh 的行为方式并对结果感到惊讶。这是我切换到 bash 进行交互和脚本使用的原因之一。我不会告诉你也这样做,但你可能想读读 Tom Christiansen 的经典著作“csh.whynot”。

略shorter/simpler解释:

回想一下 tcsh/csh EACH 命令(包括 shell 内置命令)return 一个状态。因此 $? ($status 的别名)由 'if' 语句、'for' 循环、赋值、...

更新

从实用的角度来看,直接使用$来限制使用会更好吗?命令执行后的 if 语句:

do-something
if ( $status == 0 )
   ...
endif

在所有其他情况下,捕获变量中的状态,并仅使用该变量

do-something
something_status=$?
if ( $something_status == 0 )
   ...
endif

为了扩展 $status,即使 if 语句中的条件测试也会修改状态,因此以下对 $status 的重复测试不会永远命中 '$status == 5',即使执行 -某些东西会 return 状态 5

do-something
if ( $status == 2 ) then
  echo FOO
else if ( $status == 5 ) then
  echo BAR
endif