我知道运算符;
, &
, &&
, 或||
的相对绑定优先级bash 文档。
但是,当管道与我一起出现时,&&
我很难理解绑定强度,要么偶然发现正确的命令,要么干脆放弃。
|
与>
上述相比,其绑定优先级是什么?
我感到困惑的例子:
ls _thumbnails/video.mp4.jpg 2>/dev/null
&& echo "thumbnail already generated. Not regenerating" \
&& exit \
|| ffmpeg_thumbnail_create video.mp4 2>/dev/null \
&& ls _thumbnails/video.mp4.jpg \
&& echo "Thumbnail successfully created" \
&& exit \
|| echo "Thumbnail creation failed" \
| tee ~/thumbnails.log
上述的目标是当且仅当缩略图尚不存在时创建缩略图(我每天运行一个 cronjob)。而且我不喜欢 FFMpeg 在没有错误的情况下的大量输出(这不是 Unix 方式)。
还有其他情况,因此使用单独的语句或特定于这些程序的特殊选项的建议不会有帮助 - 我想了解绑定优先级。
答案1
简而言之<
, 、>
、 及其变体具有最高的绑定优先级(最紧绑定),其次|
是&&
、 和||
、;
和&
。因此,只有echo "Thumbnail creation failed"
被通过管道输送到tee
.
一个稍长的答案会指出最高优先级实际上就是分组,可以用括号或大括号来表示。例如,
A && (B; C)
和
A && { B; C;}
大约相当于
if A
then
B
C
fi
笔记:
- 括号给你一个子shell;即命令
B
并C
在子进程中运行。因此,诸如变量赋值或之类的命令cd
不会对父 shell 产生任何影响。大括号中的命令与该命令在同一进程中运行A
。因此,大括号结构A && { B; C;}
更接近if
-then
-else
结构。 - 在大括号语法中,有必须是 后面的空格
{
和 之前的 a;
(或&
或换行符)}
。
如需进一步阅读,请参阅shell 的控制和重定向运算符是什么?和什么时候不需要“如果”?(特别是我的答案)。
为了更进一步阅读,请参阅bash(1) 手册页和 Shell 命令语言的 POSIX 规范/定义, 具体来说第 2.9 节, Shell 命令 和部分 2.10.2, Shell 语法规则。这是试图为上述内容提供一些背景:
- 像
myVar=42
IFS= read a
date
cd /some/directory
ls -laR dir1 dir2
cat foo* > /tmp/allfoo
ls -laR dir{1,2}
find . -type f -name "foo*" -print > /tmp/output 2> /dev/null
> newfile
[ -f catfood ]
exit
都被认为是“简单命令”。
- 像
简单命令1 | 简单命令2 | 简单命令3
x=1 | od -ab
或 之类的东西ls -laR | z=0
在语法上是有效的。
管道1 && 管道2 || 管道3bash 称为“列表”,POSIX 称为“AND-OR 列表”。同样,单个“管道”甚至单个“简单命令”都被视为“AND-OR 列表”,即使它不包含 AND 或 OR。
与或列表1 & 与或列表2 ; 与或列表3命名法开始变得有点不一致。 Bash 也将这些称为“列表”; POSIX 称它们为“列表”、“复合列表”和(很少)“术语”。同样,单个“AND-OR 列表”、“管道”甚至单个“简单命令”都被视为“列表”,即使它不包含
&
或一个;
。(化合物列表)和
{ 化合物列表;}流程控制命令(`for`、`if`-`then`-`else`、`while` 等)称为“复合命令”。
在上面的示例中,将A
、B
、 和解释C
为管道可能是最有意义的。请记住,“管道”可以是单个“简单命令”;它不需要包含管道。