我有一个问题,需要用 shell 脚本编写一个程序,所以我打开了一本关于 linux 的书,其中有一章是关于 bash 脚本的。当我遇到命令时,编写一个测试脚本来测试命令似乎是个好主意,但第一个脚本不起作用,并且以其他明显的方式更改它并不能解决问题。
示例中所示的脚本是:-
#!/bin/bash
count=10
nextcount=$count + 1
echo $count
echo $nextcount
运行这个脚本的结果应该是什么
[Carl@localhost bin]$ testscript
10
11
然而实际结果是
[Carl@localhost bin]$ testscript
/home/Carl/bin/testscript: line 3: +: command not found
10
错误消息表明“+”号被解释为命令而不是加法运算符。
如果我删除“+”号周围的空格,以便脚本变成
#!/bin/bash
count=10
nextcount=$count+1
echo $count
echo $nextcount
[Carl@localhost bin]$ testscript
10
10+1
第 3 行语句不是将 1 加到 10 得到 11,而是连接“10”、“+”和“1”
将 line3 更改为读取nextcount=$count +1
或nextcount=$count+ 1
也不起作用。
在脚本编写教科书中的第一个示例中发现无法解决的问题是不应该发生的。我要疯了吗?
答案1
一如既往,在 shell 中进行赋值才不是接受空格(参见:shell 脚本中变量赋值中的空格):类似于var=foo bar
运行命令bar
并var
设置为foo
.或者在您的情况下,命令是+
,这很好,因为+
对 shell 没有特殊含义(无论如何不在这种情况下)。另外,var=1+1
将右侧视为字符串1+1
,因为加号只是一个常规字符。如果它有特殊含义(例如;
、 或(
),则需要引用它。
在 shell 中进行算术运算的标准方法是扩展$(( ... ))
,因此要添加数字并将其分配给变量,请使用:
anothervar=$((var + 1))
如果您使用的是 Bash/ksh/zsh 并且只想循环恒定数量的迭代,您可以使用:
for (( i = 0; i < 10 ; i++)); do something ; done
(for i in {1..10}
也可以,但在 Bash 中,变量扩展在大括号扩展内不起作用。)
答案2
使用算术表达式语法进行数学运算:
count=10
(( nextcount = count + 1 ))
答案3
通过使用以下命令,可以做一些与您所展示的类似的事情declare -i
:
declare -i nextcount
nextcount=$count+1
声明变量nextcount
这声明了具有整数属性的算术评估每当分配时都会自动对其执行。 (help declare
在 bash 中运行或看这里了解详细信息。)这不是标准 POSIX shell 功能,但 bash 支持它。
任务不需要立即执行declare
命令。如果是这样,您可能更喜欢在declare
命令中执行此操作,如下所示:
declare -i nextcount=$count+1
任何带有整数和的算术表达式算术运算符是支持的。如果操作符有被 shell 以另一种方式特殊解释的风险,您可以引用表达式来防止这种情况发生。请记住,您正在将文本分配给变量;对该文本进行算术评估。再例如,此命令$x
将扩展为13
:
declare -i x='2 * 7 - 1'
即使您删除了空格,您也会希望引用它,因为*
否则会导致它被解释为全局, 触发文件名扩展。请注意,周围仍不能有空格=
。
不过,您通常可能不会这样做。通常它使用起来更简单、更优雅、更具可读性算术展开(与$
) 或算术评估(没有$
) 相反,正如其他答案所暗示的那样。我提出这里展示的方法并不是为了鼓励您喜欢它,而是主要是因为它是最接近您的书所展示的实际执行 shell 算术的方法。
算术表达式——我指的是使用 shell 算术计算的表达式,因为它们位于$((
))
or内部((
))
——允许您在其周围使用=
空格。从语法上讲,=
命令中的与命令中的((count = 10))
的工作方式不同。=
count=10
如果x
有整数属性(declare -i x
),你甚至可以编写这样的代码来为多个变量赋值,尽管我建议不要这样做,因为它很令人困惑:
x=y=z=10
如果你想知道它的作用,这里有一个提示——它做了同样的事情:
x='y = z = 10'
这将字符串y = z = 10
(或者,在第一个示例中,y=z=10
)分配给x
。至少x
具有整数属性很重要。假设确实如此,则将该文本计算为算术表达式。子表达式z = 10
分配10
给z
,但该子表达式还有一个值 ,10
该值分配给y
。那满的表达式是对 的赋值y
,也有一个值 still 10
。
请注意,第一个=
是执行普通的 shell 变量赋值,而其他的是算术赋值运算符。这是不是第二种形式是特殊的(通过引用可以包含空格)。在 中x=y=z=10
,第一个 es=
的含义也与其他两个=
es 不同,尽管您碰巧使用它们来实现相同的目标。这可能会令人困惑。我建议不要写这样的东西,除非出于实验目的而以交互方式编写。你可以写这个命令来代替:
((x = y = z = 10))
这是简单的算术评估。所有三个=
符号都是算术赋值运算符。如果您使用整数属性声明了部分或全部变量(我经常提倡这样做),那仍然没问题,但您不需要这样做。
类似地,bash 有一个+=
通常附加文本的运算符:
$ x=foo
$ x+=bar
$ echo "$x"
foobar
(某些行上的前导$
字符是我的提示符。我将它们包含在这里是为了区分我给 bash 的输入和它产生的输出。)
但分配变量的属性会影响+=
执行的操作。+=
通常用于扩展索引数组:
$ a=(foo bar baz)
$ a+=(quux)
$ echo "${a[@]}"
foo bar baz quux
当将具有整数属性的变量分配给 with 时+=
,将执行就地加法:
$ declare -i y=7
$ y+=2
$ echo "$y"
9
但 bash 也有+=
算术运算符,我建议在大多数情况下使用算术运算符。也就是说,如果y
保存值2
,您可以这样写,将 的值增加y
2:
((y += 2))
它还具有其他传统的复合赋值运算符(C 语言中存在的运算符)。例如,假设我想要减少的值y
乘以 3。这不起作用:
$ y-=3
y-=3: command not found
但这有效:
$ ((y -= 3))
$ echo "$y"
6
或者我可以这样做,既更改y
并打印新值:
$ echo "$((y -= 3))"
6