我尝试过网络搜索和该网站上的搜索,但只发现 bash 中字符串使用空格的问题。不过,我想了解 bash 脚本中使用空格背后的一般逻辑,以便我可以更好地记住正确的用法:哪里是强制性的,哪里相反。
几个例子:强制[ $i == b ]
,相反var1="foo"
答案1
不过我想了解 bash 脚本中使用空格背后的一般逻辑
在分隔命令参数和分隔命令时必须使用空格关键词(或保留字,取决于来源)。这些 是{
,,,,,,,,等等。}
!
if
for
do
done
周围的空白不是强制的运营商。这些至少是语句终止符;
和&
;条件运算符&&
和||
;所有重定向运算符等>
;<<
以及括号(
和)
。重定向运算符前面的可选文件描述符编号不能用空格分隔,但运算符周围的额外空格通常并不重要。
所以,这些都很好:
true;true
cat<<file
true&&false
tac|rev
f()(echo foo)
这些不是:
if !somecmd; then ...
f(){echo foo}
第一个将查找命令!somecmd
,而不是运行somecmd
并反转退出状态。第二个不起作用,因为关键字 '{' 和}
必须是单独的单词,并且它们仅在命令开头被识别。它可能是例如f(){ echo foo;}
。
如果 course 不能作为if
语句,因为如果if
从单词的开头选择 ,则调用的程序ifconfig
将很难使用:
ifsomecmd;then ...
(尽管这一点可能是显而易见的,除非您习惯使用 Fortran。)
那么,你怎么知道这(
是一个运算符而{
不是一个运算符呢?你通过死记硬背来学习它。这种差异可能是由于历史原因造成的,很多事情都是如此。看:为什么 POSIX Shell Grammar 中的大括号命令组在左大括号后需要空格?
该问题的答案有更多关于运算符和关键字的讨论,并附有参考文献,因此请阅读它们。
不过,以上内容都不能真正帮助您区分作业foo=bar
和测试之间的区别[ "$foo" = bar ]
。
这里的关键是,[
就像常规命令一样,它将其运算符和操作数作为不同的参数,并且不会真正查看它们的内部。就像ls -l /somedirectory
需要空格来分隔其参数(-l
和/somedirectory
)一样, 也是如此[
。这对括号不是 shell 语法的一部分(或语法),并且 也不是=
,与大多数实际编程语言中的等效构造不同。
至于任务,他们有点棘手。赋值不需要单独出现在命令行上(它们可以与命令一起使用),并且一行上可以有多个赋值。就像这样:
$ foobar=123 foofoo=456 env|grep foo
foofoo=456
foobar=123
它的工作方式(大致)是,shell 将命令拆分为单词(上面的单词是foobar=123
,foofoo=456
和env
),并查看最初的单词,看看它们是否看起来像赋值。这两个确实如此,但在这里,没有赋值,只是一个普通的参数echo
:
$ echo foo=bar
foo=bar
我想 shell 语法在这方面可能有所不同,但是支持这样的事情,即有两个赋值和一个没有参数的命令可能看起来很奇怪(好吧,除非你习惯了 Lua):
foobar = 123 foofoo = 456 env
答案2
关键是空格分隔字,除非引用,并且字是你必须考虑的:
基本上,shell 执行以下操作:
和:
简单命令是最常遇到的命令。它只是一系列由空格分隔的单词,由 shell 的控制运算符之一终止[.] -3.2.1 简单命令
和:
- 解析器标记为变量赋值(命令名前面的词)和重定向的词被保存以供稍后处理。
- 不是变量赋值或重定向的单词被扩展[...]。如果扩展后仍有任何单词,则第一个单词将被视为命令名称,其余单词将被视为参数。
请注意它是如何表述“标记为变量赋值的单词[...]”。因此变量赋值必须是单个单词,因此以下是只是变量赋值:
var=value
✓var=" value"
✓
但以下情况则不然:
var= value
✗(两个词:变量赋值var=
- 赋值空字符串 - for 命令value
)var =value
✗(两个词:var
带参数的命令=value
)var" =value"
✗(一个字:但变量名不能加引号,所以这是名为 的命令var =value
)"var=value"
✗(一个字:但变量名不能加引号,所以这是名为 的命令var=value
)
现在 for [ var = value ]
,[
是一个命令(与 相同的命令test
),它期望测试和测试的操作数为单独的论点。这样,您可以执行诸如[ "$var" = "$value" ]
or 之类的操作test "$var" = "$value"
,其中,例如,var="a = b"
andvalue="b = c"
可以包含看起来像测试的内容,但实际上并非如此,因为每个都是单个参数。
因为参数必须是单独的单词,所以 周围需要空格=
。这也是为什么"$var"
and"$value"
必须被引用的原因,否则 shell 会将它们分成单独的单词,并且[
会失败。