Command Files
可以把任何命令行直接输入的命令放到一个文件中,给文件赋予可执行权限后就能直接运行,这就是 shell 脚本。
Commnets
shell 使用 #
注释。
Variables
和其他编程语言一样,shell 也有变量。使用 variable=value
的形式定义变量。
注意:
- 等号两边不能有空格
- shell 没有数据类型的概念,统一当作字符串处理
count=1
这里的 1 会当作字符
因为 shell 是一种解释型的语言,可以直接在终端上给变量赋值。
显示变量的值
使用 echo
显示变量的值 echo $var
,对 shell 来说 当 $
符号后跟几个字符时,$
是有特殊含义的,shell 在执行脚本时会进行 variable substitution
。
变量可以用在任何命令和任何地方,并且在执行之前会被 shell 替换。
ls $my_bin
,cd $my_bin
,number=99
echo There are $number cats
。
1 | command=wc |
shell 先进行变量替换再执行命令。
变量可以赋值给其他变量
1 | val1=10 |
记住无论什么时候想使用存储在变量中的值都需要使用 $
符号。
Undefined Variables Have the NULL Value
打印未定义的变量会发生什么?会报错吗?echo $nosuch
不会报错,但是 shell 打印出东西了吗? echo :$nosuch:
,对于未指定值的变量,没有字符被 shell 替换。
A variable that contains no value is said to be undefined and contain the null value.
当 shell 进行变量名替换时,如果发现有些变量是 null,那么直接从命令行移除这个变量。
wc $nosuch -l $nosuch $nosuch names
shell 扫描命令行,使用 null
替换 $nosuch
,当扫描结束后,命令变成 wc -l names
,这就是为什么这个命令能工作的原因。
但是有时就想使用空值初始化变量怎么办?dataflag=
更好的做法是 dataflag=""
or dataflag=''
。后两个和第一个效果一样,但是更实用。
注意 dataflag=' '
和前面的是不相同的,dataflag
此时保存的是一个空格。
Filename Subsitution and Variables
有个 puzzle,x=*
x 是什么,shell 会把字符 *
存到变量 x
中,还是把当前文件夹下所有的文件名存到 x
里面呢?答案是后者。
1 | ls |
从这个例子中可以学到很多,是在执行 x=*
的时候保存了文件名还是执行 echo $x
时 shell 执行替换呢?
shell 在定义变量时并不会执行 filename subsitution
,因此 x=*
,只会把 *
赋值给 x
,在变量替换后执行 echo
前会进行文件名替换。
执行顺序:
- shell 扫描命令行,使用
*
替换变量 - shell 再次扫描命令行,遇到
*
,然后使用当前目录下所有文件名替换*
- shell 开始执行
echo
,把文件名当参数传给echo
evaluation 的顺序是非常重要的,首先进行变量替换,再进行文件名替换,然后把命令行解析为参数。
The ${variable}
Construct
假设有个变量保存了文件名,现在希望重命名文件,新的文件名加上 x
。
mv $fn $fnx
这样做显然不行,shell 会把 $fnx
当作变量替换,可以使用构造器。
mv $fn ${fn}x
这样就消除了任何歧义。
对于这种形式的变量构造器,还有很多函数可以使用,比如提取子集,如果变量未定义给定值等操作。
Built-in Interger Arithmetic
POSIX 标准 shell 提供了一种叫做 arithmetic expansion
机制来操作变量上的整数运算。有些老的 shell 不一定支持。
arithmetic expansion
的格式是 $((expression))
,expression 是使用 shell 变量和操作符的表达式。 有效的变量是只包含数字的变量,前后空格是允许的,有效的操作符是从 C 语言借鉴来的。
$(()) Operators
有效的操作符号很多,包括基本的 6 个操作符:+
、-
、*
、/
、%
和 **
,还包括 +=
、-=
、*=
、/=
、i++
、i--
等等。
还可以基于不同进制的数字进行进制转换,比如八进制的 100 echo $((8#100))
,二进制 echo $(( 2#101010101010101010 ))
。
计算表达式会在命令行被替换,比如 echo $((i+1))
,对 shell 变量 i
中的值加一,并打印结果,注意这里的 i
不需要用 $
来引用,因为 shell 知道只有 operators、numbers 和 变量
才能出现在 arithmetic expansion
中。
如果变量没有值或者是空,那么会使用 0
替代,echo $((a=a+1))
,a
未定义,会当作 0
处理,结果 a
中保存了 1
。
注意赋值符号也是有效的 operator
,所以 a
的值是 1
,同样可以使用括号来保证计算的优先级。
echo $((i=(i+10)*j))
,同样可以直接赋值,i=$((i * 5))
注意计算表达式中的空格是无所谓的,但是 shell 赋值必须没有空格。
$((i++))
i 的值是会变的,同样可以使用逻辑运算,result=$((i>=10 && i<=100))
,真是 1 ,假是 0。