源自实验楼高级 bash 脚本编程指南课程。
shell脚本的第一行通常为#!/bin/bash
,其中#!
用于指定当前脚本的解释器,我们这里使用的是bash,所以应该指明bash的完整路径:/bin.bash
在shell中,转义的#
不能作为注释。
#!/bin/bash
echo "The # here does not begin a comment."
echo 'The # here does not begin a comment.'
echo The \# here does not begin a comment.
echo The # here bigins a comment.
echo $(( 2#101011 )) # 数制转换(使用二进制表示),不是一个注释,双括号表示对于数字的处理
输出结果为:
The # here does not begin a comment.
The # here does not begin a comment.
The # here dose not begin a comment.
The
43
使用分号可以在同一行上写两个或者两个以上的命令。
#!/bin/bash
echo hello; echo world!
filename=ttt.sh
if [ -e "$filename" ]
then
echo "File $filename exists."; cp $filename $filename.bak
else
echo "File $filename not found."; touch $filename
fi; echo "File test complete."
结果输出为:
hello
world!
File ttt.sh exists.
File test complete.
也就是说shell中一行中只能包含一条命令,但是加入分号之后可以包含多条命令,类似地也可以把在if [ condition ]
后面加上一个;
然后把then
和if
放到同一行中。
bash中的source命令用于在当前bash环境下读取并执行FileName.sh
中的命令。
"STRING"将会解释STRING中的大部分特殊的字符。
'STRING’将会阻止STRING中所有特殊字符的解释。
#!/bin/bash
VALUE='test'
echo "$VALUE"
echo '$VALUE'
输出结果为:
test #双引号中特殊字符被解释了
$VALUE #单引号中的特殊字符直接输出了
文件名路径分隔符,分割文件名不同的部分。也可用作除法算术操作符。注意在linux中表示路径的时候,许多个/
跟一个/
的作用是一样的。
一种对单字符的引用机制。\X
将会转义字符X
,等价于'X'
。\
经常用来转义"
以及'
,这样双引号和单引号就不会被解释成特殊含义了。
反引号中的命令会优先执行,如:
$ cp `mkdir back` test.sh back
$ ls
会先创建back目录,然后复制test.sh到back目录。
等价于"NOP"
(no op,一个什么也不干的命令)。也可以被认为与shell的内建命令true作用相同。":"
命令是一个bash的内建命令,它的退出码(exit status)是0。
例如:
#!/bin/bash
while :
do
echo "endless loop"
done
等价于:
#!/bin/bash
while true
do
echo "endless loop"
done
因此":"
也可以用在if-else中作为占位符。
与>
重定向操作符结合使用时,将会把一个文件清空,但是并不会修改这个文件的权限。如果之前这个文件并不存在,那么就创建这个文件。
: > test.sh
cat /dev/null > test.sh
这两条命令的作用相同。
与>>
重定向操作符结合使用时,将不会对预先存在的目标文件产生任何影响。如果这个文件之前并不存在,那么就创建它,>>
相当于c++文件中的append,而:
相当于空命令,所以不会对重定向的文件产生任何影响。
:
还在/etc/passwd
和$PATH
变量中做分隔符,如:
/home/yushang/.local/bin:/usr/local/sbin:/usr/local/bin
在一个双括号结构中,?
相当于C语言中的三元操作符,如:
#!/bin/bash
a=10
(( t=a<50?8:9 ))
echo $t
输出结果为:
8
用于变量替换,在字符串前面加上$
将字符串替换成变量。
在括号中的命令列表,将会作为一个子shell来执行。
在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的。父进程中,也就是脚本本身,将不能读取子进程中创建的变量,也就是在子shell中创建的变量。如:
#!/bin/bash
a=123
( a=321 )
echo $a
输出结果为:
123
在圆括号中的变量a
,更像是一个局部变量。
例如:
#!/bin/bash
arr=(1 2 3 4 5 6)
echo ${arr[3]}
输出结果为:
4
例如:
#!/bin/bash
if [ ! -w 't.txt']
then
touch t.txt
fi
echo 'test text' >> t.txt
cp t.{txt,back}
输出结果为:
$ ls
$ cat t.txt
$ cat t.back
大括号中不能留有空白,除非这个空白被引用或者转义。
代码块,又被称为内部组,这个结构事实上创建了一个匿名函数(一个没有名字的函数)。然而,与标准函数不同,在其中声明的变量,对于脚本其它部分的代码来说还是可见的。
例如:
#!/bin/bash
a=123
{ a=321; }
echo $a
输出结果为:
321
大括号中的;
不能少,不然好像会出现syntax error: unexpected end of file.
条件测试表达式放在[]中。在shell的控制流程中经常使用。
在一个array结构的上下文中,中括号用来引用数组中的每个元素的编号。与10.2中的例子类似,当然可以通过索引得到数组中的具体元素并且修改元素的值。
test.sh > filename
:重定向test.sh
的输出到文件filename
中。filename
中之前存在的内容将会被覆盖掉。
test.sh &> filename
:重定向test.sh
的stdout(标准输出)和stderr(标准错误)
到filename
中。
test.sh >&2
:重定向test.sh
的stdout
到stderr
中。
test.sh >> filename
:把test.sh
的输出追加到文件filename
中。如果filename
不存在的话,将会被创建。
分析前面命令的输出,并将输出作为后边命令的输入。这是一种产生命令链的好方法。例如:
#!/bin/bash
tr 'a-z' 'A-Z' #将小写字母转为相应的大写字母
exit 0
ls | ./shu.sh
输出结果为:
1
ANNOTATION.SH
DA.SH
FENHAO.SH
SHU.SH
T.BACK
T.TXT
TEST.SH
TEST1.SH
TTT.SH
WENHAO.SH
XIAO.SH
XIE.SH
YINHAO.SH
在所有的命令内,如果想要使用选项参数的话,前面都要加上-
,例如if-else的condition语句中。
没懂~
表示home目录