我对bash编程有点挣扎,因为我似乎不理解语法规则。例如:
read confirm
if [ "$confirm" == "yes" ]; then
echo "Thank you for saying yes"
else
echo "Why did you say no?"
fi
在此代码中,您可以使用多种表单来执行相同的操作:
"$confirm" == "yes"
$confirm == "yes"
"$confirm" == yes
$confirm == yes
那么规则是什么?除此之外,它非常严格,所以如果你在'['和'''之间没有空格的情况下编写上面的if语句,你就会收到错误。所以我的问题:
的问候,
Rafid
答案 0 :(得分:12)
规则很简单但很微妙。你给出的例子并不完全等同,它们的含义略有不同。有关相当好的参考,您可以阅读Shell Command Language,其中包含POSIX shell。大多数shell,当然包括bash,zsh和ksh,都是POSIX shell,并且至少会实现那里列出的内容。有些shell可能符合规范的早期版本,或者类似但不符合。
如果您正在学习Unix shell脚本,则需要记住的主要规则是:表达式由空格分隔。从技术上讲,它们由变量$ IFS中列出的任何字符分隔,但在正常情况下这相当于空格。
如果你在bash中说["$a"="$b"]
,shell会尝试将整个字符串作为命令读取,评估$ a和$ b。假设$a
的值是文字a
,$b
的值是文字b
,shell会尝试执行名为[a=b]
的命令,这是一个合法的文件名。引号被shell解释为特殊但[
不是,因为它只是作为单独的标记编写时才特殊。它没有被空格分隔。
你在shell中看到和做的几乎所有事情都是一个命令。字符[
不是语法,而是命令。命令采用以空格分隔的参数。这些参数意味着什么取决于命令,而不是shell。在C if ( a == b )
由解析器处理,除了a和b的值。在bash if [ "$a" == "$b" ]
中首先由shell解析,它评估变量$ a和$ b,然后执行命令[
。有时这是一个shell内置命令,有时它实际上是一个单独的可执行文件(在系统中查找/bin/[
)。这意味着a == b ]
根本不会被bash解释,而是一种由[
解释的特定于域的语言,也称为test
。实际上,您可以改为编写if test "$a" == "$b"
。在此表单中,test
不需要关闭]
,但其他所有内容都相同。要查看test
对这些参数的处理方式,请阅读help test
或man test
。
在学习Unix shell脚本时需要记住的另一条规则是:首先扩展变量,然后再评估命令。这意味着如果变量中有空格,例如foo="a b"
,那么shell将在变量展开后看到空格:ls $foo
本身会抱怨它无法找到文件{{1它无法找到文件a
。为了获得您可能期望从其他语言中获得的行为,您几乎总是希望引用您的变量:b
,它指示shell将扩展变量视为单个字符串而不是重新标记化。
Shell脚本充满了奇怪的东西,但它并非不合理(至少在大多数情况下不是这样)。有些历史疣确实存在但是一旦你掌握了基础知识,就没有太多的规则可以记住了。只是不要指望它像传统的C语言那样运作,你也不会太惊讶。
答案 1 :(得分:2)
一个问题是,如果你这样做:
if [ $foo == "bar" ] ...
然后$ foo为空,您将收到语法错误。这可以通过例如解决。
# prepend both with an 'x' (or any other char)
if [ x$foo == "xbar" ] ..
# or enclosing in quotes (not sure this works on all shells)
if [ "$foo" == "bar" ] ...
将内容放在引号内也可以确保保留空格以进行比较。
今天,还有其他更高级的方法可以在if语句中使用表达式,例如双括号
if [[ $foo == bar ]]
有关详细信息,请参阅this SO question。
至于选择学习哪种剧本方言,我建议学习bash,因为这是迄今为止最常见的一种。如果你想编写可移植脚本,那么将自己局限于旧的'sh'方言,这种方言不是很先进,但应该得到几乎所有unix shell的支持。
C-shell对于C风格的程序员来说可能更容易学习语法(因为语法与C更接近),但它在野外不太常见
答案 2 :(得分:2)
bash中最基本的语法规则是:
<command> <space>+ <arguments>
也就是说,命令和参数必须用一个或多个空格分隔。 [
是一个命令,因此在错误之后省略空格。
至于哪个是“更好”,我回应j_random_hacker的评论:
所有shell语言都很糟糕,虽然有些语言比其他语言更糟糕,并且都比Windows的cmd.exe好。我的建议是坚持使用最受欢迎的bash。
答案 3 :(得分:2)
以下是bash提示的一些有用链接:
答案 4 :(得分:2)
为了真正安全,你应该使用:
"$confirm" == "yes"
因为这可以确保bash将两个值都视为字符串。否则,它们会受到扩展/替换的影响,这可能会产生意外结果或/和语法错误。
当你省略开括号和引号之间的空格时的语法错误 - 开括号“[”只是“test”shell内置的别名。所以你的情况也可以写成:
read confirm
if test "$confirm" == "yes"; then
echo "Thank you for saying yes"
else
echo "Why did you say no?"
fi
实际上,在某些系统上,/ usr / bin中有一个名为[的文件,它链接到test命令(如果某些shell没有“[”作为shell内置命令)。
答案 5 :(得分:2)
所有shell语言都很糟糕,虽然有些语言比其他语言更糟糕,并且都比Windows的cmd.exe好。我的建议是坚持使用最受欢迎的bash。 man bash
应该为您提供(巨大的,错综复杂的)语法规则。
答案 6 :(得分:1)
我建议您查看tcsh。它的语法更类似于C.
答案 7 :(得分:1)