我不确定{}
和之间的区别()
。
在下面的代码片段中:
#!/bin/bash
set -e
echo "two">file.txt
ARRAY=(one two three)
rc=0
for i in ${ARRAY[@]}; do
echo "grepping $i "
#grep "$i" file.txt || (echo "failed grep" && exit 1) <--1
#grep "$i" file.txt || {rc=$? && echo "failed grep"} <--2
grep "$i" file.txt || (rc=$? && echo "failed grep") <--3
done
exit $rc
命令 2 是唯一不起作用的命令。但我期望它应该有效,并且命令 1 不会按照接受的答案终止脚本这里
有人可以解释一下发生了什么事吗?
答案1
在bash
大多数 POSIX shell 中, while(
和)
是 shell 语法中的特殊标记字符(无论它们出现在哪里,都会被特殊对待,包括作为多字符标记的一部分,如((
, $(
, <(
, $((
, <#((
...),{
并且}
are not ,除非组合使用特殊标记字符如 in ${
, or 用于特殊{x,y}
or{x..y}
形式。
您会注意到 whileecho )
给出了错误,echo }
但没有输出}
,因此}
in{echo}
不可能关闭{
。
具体来说,{
和}
是关键词喜欢while
,time
,!
。它们只能出现在需要命令的地方(在第一个近似值中)并且只能出现在单独的单词中。
{echo
将是{echo
命令,而不是{
后跟的关键字echo
。就像while[
命令while[
而不是while
后面跟着的关键字一样[
。
您可以在 和 都被分隔且处于命令位置的情况下使用或,但不能{ echo;}
使用。{<file cat;}
{
}
{echo}
但也有一些例外。您会注意到,{(echo test)}
即使在关闭之后)
除了重定向之外通常不会发生任何事情,而且它}
不在命令位置,它也可以工作。对于{ { echo; } }
第二个}
不在指挥位置的情况也是如此。
{ echo; ! }
或{ echo; time }
在 ksh93 中工作,但不在bash
(即使它们}
处于命令位置。
一个例外是在可能的情况下zsh
尝试将{
和识别}
为标记。也就是说,当处于指挥位置时和在某些有限的情况下。{echo}
在那里工作,但{{echo}}
不是例如(尽管{{echo} }
确实如此)。{echo,foo}
就像{ echo,foo;}
那里而不是echo foo
bash/ksh 一样。
<file {head;head}
可以工作,zsh
但在其他 shell 中不起作用。
这是由IGNORE_BRACES
和IGNORE_CLOSE_BRACES
选项控制的。
答案2
是{}
冒号分隔格式的复合语句的占位符,bash
并()
创建一个子 shell 上下文,在该子 shell 上下文中,变量更新不会反映在大括号之外。
$?
在使用grep
或任何其他 shell 命令时,您甚至不必弄乱返回代码值。您可以通过抑制控制台输出(通常0
在命令成功时返回命令)来直接在 if 条件中使用它们的退出代码。您grep
可以通过启用该-q
标志来做到这一点
if grep -q "$i" file.txt; then
printf "grep suceeded\n"
else
printf "grep failed\n"
fi
如果您想手动存储退出代码,使用复合语句的想法是正确的(使用子 shell 在这里不起作用!)。你只需要用一个结束复合语句;
grep "$i" file.txt || {rc=$? ; echo "failed grep" ; }
现在退出代码可供rc
您使用。或者更简单地说,您可以在 echo 本身中使用该变量
grep "$i" file.txt || echo "failed grep with rc: $?"
要使用 sub-shell 添加到答案中()
,用于存储变量上下文是不是一个很好的做法。所附命令完成后,shell 很快就会终止。
例如,使用下面这个简单的字符串相等运算
str='foo'; rc=0
[[ $str == *doo* ]] || { rc=$?; echo "string comparison failed" ; }
echo "$rc"
将正确反映该rc
值,但在子 shell 的情况下,这将不起作用
str='foo'; rc=0
[[ $str == *doo* ]] || ( rc=$?; echo "string comparison failed" )
echo "$rc"
将反映应该在子 shell 内0
返回 set 时的值。1
[与实际问题无关]
您应该始终引用您的数组扩展。不这样做会将包含空格或其他特殊字符的数组元素拆分为单独的单词,而不是将它们视为一个单词
for i in "${ARRAY[@]}"; do