对于Shell脚本的编写,可以使用任何文本编辑器,利用常用的文本编辑器、UltraEdit、Editplus、Gedit等都可以!
对于Shell脚本的书写,约定俗成,第一行必须如下所示:(务必放在文件的第一行)
1
2
|
#!/bin/sh
...
|
符号#!用来告诉系统执行该脚本的程序,这里使用/bin/sh。编辑结束并保存;这里最好使用“!/bin/bash”而不是“!/bin/sh”,如果使用tc shell改为tcsh,其他类似。
如果要执行该脚本,必须先使用chmod命令打开脚本的执行权限,如下:
1
|
chmod
+x yourScriptName
|
注释: 在进行shell编程时,以 # 开头的句子表示注释;
变量: 在其他编程语言中你必须使用变量。在shell编程中,所有的变量都由字符串组成,并且大家不需要对变量进行声明;当你要赋值给一个变量,首先熟悉如下知识;
1.需要给变量赋值时,可以这么写: 变量名=值
1-1. 首个字符必须为字母(a-z,A-Z)
1-2 中间不能有空格,可以使用下划线(_)
1-3 不能使用标点符号
1-4 不能使用bash里的关键字(可用help命令查看保留关键字)
2. 要取用一个变量的值,只需在变量名前面加一个$ ( 注意: 给变量赋值的时候,不能在”=”两边留空格 )
3. echo 输出(打印)
OK,书写第一个完整Shell脚本:
1
2
3
4
5
6
|
#!/bin/sh
#对变量赋值:
himi=
"HelloShell"
#等号两边均不能有空格存在
# 现在打印变量a的内容:
echo
"A is:"
echo
$himi
|
OK,终端命令&输出如下:
Last login: Sat Apr 14 14:16:13 on ttys000
mac:~ Himi$ cd /Users/Himi/Desktop/
mac:Desktop Himi$ chmod +x himi
mac:Desktop Himi$ ./himi
A is:
HelloShell
mac:Desktop Himi$
需要大家注意的是有时候变量名可能会和其它文字混淆,比如:
#!/bin/sh
#对变量赋值:
himi=”test” #等号两边均不能有空格存在
echo $himi
echo $himi A
echo “A $himi”
#注意混淆
echo “A $himi_OK”
#正确写法:
echo “A ${himi}_OK”
终端执行&打印:
1
2
3
4
5
6
7
|
mac:Desktop Himi$ .
/himi
test
test
A
A
test
A
A test_OK
mac:Desktop Himi$
|
童鞋们可以看到《 echo “A $himi_OK” 》这里没有正常打印出来,这是由于shell会去搜索变量himi_OK的值,而实际上这个变量此时并没有值。这时,我们可以用花括号来告诉shell要打印的是himi变量;
还需要注意shell的默认赋值是字符串赋值。比如:
1
2
3
4
5
|
#!/bin/sh
#字符串赋值:
_int=19
_tot=$_int+89
echo $_tot
|
打印的_tot不是108 !而是 19+89 !出现此的原因就是因为Shell默认是字符串赋值,应该需要计算应该先熟悉如下几个知识:
let 表示数学运算
$[] 表示将中括号内的表达式作为数学运算先计算结果再输出。
expr 用于整数值运算,每一项用空格隔开
上面前两种方式在bash下有效,在sh下会出错。
OK,知道这些就可以重新将刚才的脚本改写成如下形式:
1
2
3
4
5
|
#!/bin/sh
#字符串赋值:
_int=19
_tot=$[$_int+89]
echo
$_tot
|
3种形式输出的结果都是 108 ;
将到这里就不得不说下Shell的算术运算仂,对于Shell种的运算中,大家需要知道:
C shell只支持整数的运算;
运算符如下图所示:
注意:
1.运算符两侧都必须有空格!!
2.C shell不支持浮点运算符(ps.如果您想要执行更加复杂的数学运算,可用UNIX的实用程序bc和nawk)
if语句:
[ -f "somefile" ] :判断是否是一个文件
[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
[ -n "$var" ] :判断$var变量是否有值
[ "$a" = "$b" ] :判断$a和$b是否相等
示例代码:
1
2
3
4
5
6
7
8
9
10
11
|
#!/bin/sh
varOne=1
varTwo=2
varThree=3
if
[
"$varOne"
=
"$varTwo"
];
then
echo
"varTwo:$varTwo"
elif
[
"$varOne"
=
"$varThree"
];
then
echo
"varThree:$varThree"
else
echo
"varOne:$varOne"
fi
|
务必注意,[]比较的时候其括号前后的空格别忘了! = 等号前后也要有空格也要注意;
&& 和 || 操作符:
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
#!/bin/sh
varOne=1
varTwo=2
varThree=3
if
[
"$varOne"
=
"$varThree"
] || [
"$varOne"
=
"$varTwo"
];
then
echo
"|| 进入"
else
echo
"No || 进入"
fi
if
[
"$varOne"
=
"$varOne"
] && [
"$varOne"
=
"$varTwo"
];
then
echo
"&& 进入"
else
echo
"No && 进入"
fi
|
case 语句:
须知:
case表达式可以用来匹配一个给定的字符串,而不是数字(可别和C语言里的switch…case混淆)。
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
|
#!/bin/sh
ftype=`
file
"$1"
`
# Note ' and ` is different
case
"$ftype"
in
"$1: Zip archive"
*)
unzip
"$1"
;;
"$1: gzip compressed"
*)
gunzip
"$1"
;;
"$1: bzip2 compressed"
*)
bunzip2
"$1"
;;
*)
echo
"File $1 can not be uncompressed with smartzip"
;;
esac
|
特殊变量$1,该变量包含有传递给该脚本的第一个参数值,也就是说,$1 就是字符串 articles.zip。
select 语句:
select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的值中进行选择:
1
2
3
4
|
select
var
in
... ;
do
break
;
done
.... now $var can be used ....
|
示例代码:
1
2
3
4
5
6
7
|
#!/bin/sh
echo
"What is your favourite OS?"
select
var
in
"Linux"
"Gnu Hurd"
"Free BSD"
"Other"
;
do
break
;
done
echo
"You have selected $var"
|
如果 以上脚本运行出现 select :NOT FOUND 将 #!/bin/sh 改为 #!/bin/bash 该脚本的运行结果如下:
1
2
3
4
5
6
7
|
What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux
|
while/for 循环:
示例代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
#!/bin/sh
varOne=1
varTwo=1
# while
while
[
"$varOne"
=
"$varOne"
];
do
echo
"while Done"
break
done
# for
for
varStr
in
H I M I ;
do
echo
"varStr is $varStr"
done
|
输出:
1
2
3
4
5
6
|
while
Done
varStr is H
varStr is I
varStr is M
varStr is I
localhost:Desktop Himi$
|
select 语句:
须知:select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的值中进行选择:
示例代码:
1
2
3
4
5
6
|
#!/bin/sh
echo
"What is your favourite?"
select
var
in
"iOS"
"Android"
"Himi"
"Other"
;
do
break
;
done
echo
"You have selected $var"
|
执行脚本后,等待用户输入,然后在终端输入你的选择,回车,如下显示:
1
2
3
4
5
6
7
8
|
What is your favourite?
1) iOS
2) Android
3) Himi
4) Other
#? 3
You have selected Himi
localhost:Desktop Himi$
|
函数:
如果你写过比较复杂的脚本,就会发现可能在几个地方使用了相同的代码,这时如果用上函数,会方便很多。函数的大致样子如下:
1
2
3
4
5
6
|
functionname()
{
# inside the body $1 is the first argument given to the function
# $2 the second ...
body
}
|
示例代码:
1
2
3
4
5
6
7
|
#!/bin/sh
himi()
{
echo
"Function is ok"
exit
0
}
himi
|
脚本调试:
最简单的调试方法当然是使用echo命令。你可以在任何怀疑出错的地方用echo打印变量值,这也是大部分shell程序员花费80%的时间用于调试的原因。Shell脚本的好处在于无需重新编译,而插入一个echo命令也不需要多少时间。shell也有一个真正的调试模式,如果脚本”strangescript”出错,可以使用如下命令进行调试:
sh -x strangescript
上述命令会执行该脚本,同时显示所有变量的值。shell还有一个不执行脚本只检查语法的模式,命令如下:
sh -n your_script
Linux Shell输入输出及几种重定向
执行一个Shell命令行时通常会自动打开3个标准文档,即标准输入文档(stdin),通常对应终端的键盘;标准输出文档(stdout)和标准错误输出文档(stderr)都对应终端的屏幕。进程将从标准输入文档中得到输入资料,将正常输出资料输出到标准输出文档,而将错误信息送到标准错误文档中。
我们以cat命令为例。cat命令的功能是从命令行给出的文件中读取资料,并将这些资料直接送到标准输出。若使用如下命令
# cat config
将会把文档config的内容依次显示到屏幕上。但是,如果cat的命令行中没有参数,它就会从标准输入中读取资料,并将其送到标准输出。例如:
# cat
Hello world
Hello world
Bye
Bye
用户输入的每一行都立刻被cat命令输出到屏幕上。
另一个例子,命令sort按行读入文档正文(当命令行中没有给出文件名时,表示从标准输入读入),将其排序,并将结果送到标准输出。下面的例子是从标准输入读入一个采购单,并将其排序。
# sort
bananas
carrots
apples
apples
bananas
carrots
这时我们在屏幕上得到了已排序的采购单。直接使用标准输入/输出文档存在以下问题:
输入资料从终端输入时,用户输入的资料只能用一次。下次再想用这些资料时就得重新输入。而且在终端上输入时,若输入有误修改起来不是很方便。输出到终端屏幕上的信息只能看不能动。我们无法对此输出做更多处理,如将输出作为另一命令的输入进行进一步的处理等。为了解决上述问题,Linux系统为输入、输出的传送引入了另外两种机制,即输入/输出重定向和管道。
1.输入重定向
输入重定向是指把命令或可执行程序的标准输入重定向到指定的文件中。也就是说,输入可以不来自键盘,而来自一个指定的文件。所以说,输入重定向主要用于改变一个命令的输入源,特别是改变那些需要大量输入的输入源。例如,命令wc统计指定文档包含的行数、单词数和字符数。如果仅在命令行上键入:
# wc
wc将等待用户告诉它统计什么,这时Shell就好像死了一样,从键盘键入的所有文本都出现在屏幕上,但并没有什么结果,直至按下【Ctrl+D】,wc才将命令结果显示在屏幕上。如果给出一个文档名作为wc命令的参数,如下例所示,wc将返回该文档所包含的行数、单词数和字符数。
# wc /etc/passwd
20 23 726 /etc/passwd
另一种把/etc/passwd文档内容传给wc命令的方法是重定向wc的输入。输入重定向的一般形式为:命令<文件名。可以用下面的命令把wc命令的输入重定向为/etc/passwd文件:
# wc < /etc/passwd
20 23 726
另一种输入重定向称为here文档,它告诉Shell当前命令的标准输入来自命令行。here文档的重定向操作符使用<<。它将一对分隔符号(分隔符号是由<<符号后的单词来定义的,本例中我们用eof来表示)之间的正文作为标准输入定向给命令。下例将一对分隔符号eof之间的正文作为wc命令的输入,统计出正文的行数、单词数和字符数。
[root@mail root]# wc << eof
> hello
> world
> are you here?
> eof
3 5 26
在<<操作符后面,任何字符或单词都可以作为正文开始前的分隔符号,本例中使用eof就作为分隔符号。here文档的正文一直延续到遇见另一个分隔符号为止。第二个分隔符号应出现在新行的开头。这时here文档的正文(不包括开始和结束的分隔符号)将重新定向送给命令wc作为它的标准输入。
由于大多数命令都以参数的形式在命令行上指定输入档的文件名,所以输入重定向并不经常使用。尽管如此,当要使用一个不接受档名作为输入参数的命令,而需要的输入内容又存在一个文档里时,就能用输入重定向解决问题。
2.输出重定向
输出重定向是指把命令(或可执行程序)的标准输出或标准错误输出重新定向到指定文档中。这样,该命令的输出就不显示在屏幕上,而是写入到指定文档中。
输出重定向比输入重定向更常用,很多情况下都可以使用这种功能。例如,如果某个命令的输出很多,在屏幕上不能完全显示,那么将输出重定向到一个文档中,然后再用文本编辑器打开这个文档,就可以查看输出信息;如果想保存一个命令的输出,也可以使用这种方法。还有,输出重定向可以用于把一个命令的输出当做另一个命令的输入(还有一种更简单的方法,就是使用管道,将在下面介绍)。
输出重定向的一般形式为:命令>文件名。例如
# ls > directory.out
# cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
表示,将ls命令的输出保存为一个名为directory.out的文件。
注:如果>符号后边指定的文件已存在,那么这个文件将被重写。
为避免输出重定向中指定文件只能存放当前命令的输出重定向的内容,Shell提供了输出重定向的一种追加手段。输出重定向与输出重定向的功能非常相似,区别仅在于输出重定向的功能是把命令(或可执行程序)的输出结果追加到指定文件的最后,而该文件原有内容不被破坏。如果要将一条命令的输出结果追加到指定文件的后面,可以使用追加重定向操作符>>。形式为:命令>>文件名。例如:
# ls *.doc>>directory.out
# cat directory.out
ch1.doc ch2.doc ch3.doc chimp config mail/ test/
ch1.doc ch2.doc ch3.doc
和程序的标准输出重定向一样,程序的错误输出也可以重新定向。使用符号2>(或追加符号2>>)表示对错误输出设备重定向。例如下面的命令
# ls /usr/tmp 2> err.file
可在屏幕上看到程序的正常输出结果,但又将程序的任何错误信息送到文件err.file中,以备将来检查用。
还可以使用另一个输出重定向操作符&>将标准输出和错误输出同时送到同一文件中。例如:
# ls /usr/tmp &> output.file
利用重定向将命令组合在一起,可实现系统单个命令不能提供的新功能。例如使用下面的命令序列
#s /usr/bin > /tmp/dir
# wc –w < /tmp/dir
459
可以统计了/usr/bin目录下的文件个数。
3.管道
将一个程序或命令的输出作为另一个程序或命令的输入有两种方法,一种是通过一个暂存文件将两个命令或程序结合在一起,例如上个例子中的/tmp/dir文件将ls和wc命令连在一起;另一种是Linux所提供的管道功能。这种方法比前一种方法更好。
管道可以把一系列命令连接起来,这意味着第一个命令的输出会作为第二个命令的输入通过管道传给第二个命令,第二个命令的输出又会作为第三个命令的输入,以此类推。显示在屏幕上的是管道行中最后一个命令的输出(如果命令行中未使用输出重定向)。
通过使用管道符“|”来创建一个管道行。用管道重写上面的例子:
# ls /usr/bin|wc -w
1789
再如:
# cat sample.txt|grep "High"|wc –l
管道将cat命令(列出一个文件的内容)的输出送给grep命令。grep命令在输入里查找单词High,grep命令的输出则是所有包含单词High的行,这个输出又被送给wc命令,wc命令统计出输入中的行数。
假设sample.txt文件的内容如下:
Things to do today:
Low:Go grocery shopping
High:Return movie
High:Clear level 3 in Alien vs. Predator
Medium:Pick up clothes from dry cleaner
那么该管道行的结果是2。
4.命令替换
命令替换和重定向有些相似,但区别在于命令替换是将一个命令的输出作为另外一个命令的参数。常用命令格式为:
# command1 `command2`
其中,command2的输出将作为command1的参数。需要注意的是这里的 ` 符号,被它括起来的内容将作为命令执行,执行后的结果作为command1的参数。例如:
$ cd `pwd`
该命令将pwd命令列出的目录作为cd命令的参数,结果仍然停留在当前目录下。
5.前台和后台
在Shell下面,一个新产生的进程可以通过用命令后面的符号“;”和“&”来分别以前台和后台的方式来执行,语法如下:
# command
产生一个前台的进程,下一个命令需等该命令运行结束后才能输入。
# command &
产生一个后台的进程,此进程在后台运行的同时,可以输入其他的命令。