是否可以在终端命令模板循环中使用 && 运算符?

是否可以在终端命令模板循环中使用 && 运算符?

我想制作一个更清晰易读的类似清晰命令列表,所以我做了一个小终端循环

for what in \
   cache \
   thumbs \
; do my template $what:clear; done

它效果很好,但是我想达到相当于

my template cache:clear && my template thumbs:clear

有没有一种方法可以轻松清晰地放置&&在这样的循环中工作,没有复杂的添加 if/else 语句到循环体检查最后一个命令退出代码并调用break if not 0?

如果条件足够你:

for what in \
   cache \
   thumbs \
; do
my template $what:clear;
if [ $? -ne 0 ]; then break; fi \
; done

答案1

你可以使用set -e

(set -e;
for what in \
   cache \
   thumbs;
do my template $what:clear; done)

set -e当命令以非零退出代码退出时,导致 shell 退出,并且不会以其他方式处理失败。上面,如果my ...失败则整个子shell退出,子shell的退出代码就是失败命令的退出代码。这适用于 shell 脚本和命令行。

另一种方法是使用析取:

for what in \
   cache \
   thumbs; do
    my template $what:clear || break
done

这样做的缺点是|| break在每个命令之后都需要,并且会吞掉指示失败的退出代码;循环for每次都会以零退出代码退出。您可以通过设置break失败来避免这种情况,这将导致for循环以退出代码 1 退出(这仍然不如上面的子 shell 方法):

for what in \
   cache \
   thumbs; do
    my template $what:clear || break -1 2>/dev/null
done

break -1导致break以非零退出代码退出,并2>/dev/null丢弃其错误消息)。

据我所知,你不能使用&&退出循环,如&& done或类似的东西。

答案2

如果发生错误,没有直接的方法可以退出循环。最明显的方法是使用while循环而不是for循环,但这并不容易与列表迭代结合起来。您需要将列表组装成一个变量,然后显式地从列表中删除元素,这使得代码变得更加复杂。

items=(cache thumbs);
while ((${#items[@]})) && my template "${items[0]}":clear; do shift items; done
((${#items[@]} == 0)) # to check if all the items were processed

比使用语句更短的编写方法if

for what in cache thumbs; do
  my template "$what":clear || break;
done

使用布尔运算符的可读性通常不如使用if,但somecommand || fallback相当惯用。

请注意,for循环总是成功。没有方便的方法来知道代码是否提前退出(您可以测试$what循环后是否是最后一项,但这需要有一种方便的方法来知道最后一项是什么,并且它不会让您知道最后一项是否是已成功处理)。

这不能很好地扩展到多个命令。您可以改为打开错误退出模式与set -e.这会导致 shell 在命令失败时立即退出(在简单的情况下 - 细节相当复杂,但在这里就足够了)。请注意,整个(子)shell 都会退出,而不仅仅是包含循环或包含函数或包含脚本。要仅退出脚本的一部分,请将该部分放入子外壳。请注意,变量修改不会在子 shell 中保留下来。

( set -e;
  for what in cache thumbs; do
    my template "$what":clear;
  done
)
# Here $? is 0 if all the mv commands succeeded and nonzero otherwise

相关内容