目录
创建脚本
在创建shell脚本文件时,必须在文件的第一行指定要使用的shell。通常井号(#)用作注释行,但第一行是个例外
#!/bin/bash
# This script displays the date and who's logged on
date
who
脚本保存在名为test1的文件中,在直接运行脚本时会出现下面问题:
$ test1
bash: test1: command not found
你要跨过的第一个障碍是让bash shell能找到你的脚本文件,只需采取以下三种作法之一:
- 将shell脚本文件所处的目录添加到PATH环境变量中;
$ PATH=$PATH:.
$ test1
- 作为解释器参数:直接运行解释器,其参数就是 shell 脚本的文件名
/bin/bash test.sh
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
- 在提示符中用绝对或相对文件路径来引用shell脚本文件(需要修改权限)
我们采用第二种方式将脚本文件的确切位置告诉shell。为了引用当前目录下的文件,可以在shell中使用单点操作符。
$ ./test1
bash: ./test1: Permission denied
$
现在shell找到了脚本文件,但还有一个问题。shell指明了你还没有执行文件的权限。下一步是通过chmod命令赋予文件属主执行文件的权限
$ chmod u+x test1
$ ./test1
Mon Feb 21 15:38:19 EST 2014
Christine tty2 2014-02-21 15:26
Samantha tty3 2014-02-21 15:26
Timothy tty1 2014-02-21 15:26
user tty7 2014-02-19 14:03 (:0)
user pts/0 2014-02-21 15:21 (:0.0) $
显示消息
在echo命令后面加上了一个字符串,该命令就能显示出这个文本字符串。echo命令可用单引号或双引号来划定文本字符串
$ echo This is a test
This is a test
$ echo Let's see if this'll work
Lets see if thisll work
$ echo "This is a test to see if you're paying attention"
This is a test to see if you're paying attention
$ echo 'Rich says "scripting is easy".'
Rich says "scripting is easy".
在脚本运行中,但如果想把文本字符串和命令输出显示在同一行中,可以用echo语句的-n参数。
#!/bin/bash
echo -n "The time and date are: "date
$ ./test1
The time and date are: Mon Feb 21 15:42:23 EST 2014
变量
-
创建变量
除了环境变量,shell脚本还允许在脚本中定义和使用自己的变量。使用等号将值赋给用户变量。在变量、等号和值之间不能出现空格。shell脚本会自动决定变量值的数据类型
var1=10
var2=-57
var3=testing
var4="still more testing"
使用一个定义过的变量,只要在变量名前面加美元符号即可
-
只读变量
readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变,也不能被删
$ readonly var1=10
$ var=11
-bash: var: 只读变量
-
删除变量
$ unset var
-bash: unset: var: 无法反设定: 只读 variable
$ unset var1
$ echo $var1
$
-
命令替换
从命令输出中提取信息,并将其赋给变量,$()格式命令输出赋给变量。shell会运行命令替换符号中的命令,并将其输出赋给变量testing
$ testing=$(date)
下面例子中,在脚本中通过命令替换获得当前日期并用它来生成唯一文件名 。today变量是被赋予格式化后的date命令的输出。+%y%m%d格式告诉date命令将日期显示为两位数的年月日的组合。
#!/bin/bash
# copy the /usr/bin directory listing to a log file
today=$(date +%y%m%d)
ls /usr/bin -al > log.$today
$ date +%y%m%d
140131
$
重定向输入和输出
-
输出重定向
最基本的重定向将命令的输出发送到一个文件中。bash shell用大于号(>)来完成这项功能:
command > outputfile
之前显示器上出现的命令输出会被保存到指定的输出文件中。如果输出文件已经存在了,重定向操作符会用新的文件数据覆盖已有文件。
$ date > test6
$ ls -l test6
-rw-r--r-- 1 user user 29 Feb 10 17:56 test6
$ cat test6
Thu Feb 10 17:56:58 EDT 2014
$
双大于号(>>)命令将输出追加到已有文件中
-
输入重定向
输入重定向符号是小于号(<):
command < inputfile
wc命令可以对对数据中的文本进行计数。默认情况下,它会输出3个值: 文本的行数; 文本的词数; 文本的字节数。
通过将文本文件重定向到wc命令,你立刻就可以得到文件中的行、词和字节的计数
$ wc < test6
2 11 60
$
还有另外一种输入重定向的方法,称为内联输入重定向。这种方法无需使用文件进行重定向,只需要在命令行中指定用于输入重定向的数据就可以了。
内联输入重定向符号是远小于号(<<)。除了这个符号,你必须指定一个文本标记来划分输入数据的开始和结尾。任何字符串都可作为文本标记,但在数据的开始和结尾文本标记必须一致。
command << marker #marker为文本标记符
data #data为输入给command的数据
marker
在命令行上使用内联输入重定向时,shell会用PS2环境变量中定义的次提示符来提示输入数据。
$ wc << EOF
> test string 1
> test string 2
> test string 3
> EOF
3 9 42
$
管道
有时需要将一个命令的输出作为另一个命令的输入。这可以用重定向来实现,只是有些笨拙。通过标准输出重定向,rpm命令的输出被重定向到了文件 rpm.list。命令完成后,rpm.list保存着系统中所有已安装的软件包列表。接下来,输入重定向将rpm.list文件的内容发送给sort命令,该命令按字母顺序对软件包名称进行排序。
$ rpm -qa > rpm.list
$ sort < rpm.list
abrt-1.1.14-1.fc14.i686
abrt-addon-ccpp-1.1.14-1.fc14.i686
abrt-addon-kerneloops-1.1.14-1.fc14.i686
abrt-addon-python-1.1.14-1.fc14.i686
acl-2.2.49-8.fc14.i686
[...]
我们用不着将命令输出重定向到文件中,可以将其直接重定向到另一个命令。这个过程叫作管道连接。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲区。
command1 | command2
$ rpm -qa | sort
abrt-1.1.14-1.fc14.i686
abrt-addon-ccpp-1.1.14-1.fc14.i686
abrt-addon-kerneloops-1.1.14-1.fc14.i686
abrt-addon-python-1.1.14-1.fc14.i686
acl-2.2.49-8.fc14.i686
[...]
可以在一条命令中使用任意多条管道
$ rpm -qa | sort | more
可以搭配使用重定向和管道来将输出保存到文件中
$ rpm -qa | sort > rpm.list
数学运算
-
方括号
在bash中,在将一个数学运算结果赋给某个变量时,可以用美元符和方括号($[ operation ])将数学表达式围起来。bash shell数学运算符只支持整数运算
$ var1=$[1 + 5]
$ echo $var1
6
$ var2=$[$var1 * 2]
$ echo $var2
12
$
-
浮点解决方案
内建的bash计算器,叫作bc。要退出bash计算器,你必须输入quit
$ bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'.
12*0.5
6.0
quit
$
浮点运算是由内建变量scale控制的。scale变量的默认值是0。在scale值被设置前,bash计算器的计算结果不包含小数位。在将其值设置成4后,bash计算器显示的结果包含四位小数。-q命令行选项可以不显示bash计算器冗长的欢迎信息。
$ bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
$
除了普通数字,bash计算器还能支持变量。
$ bc -q
var1=10
var1 * 4
40
quit
$
在脚本中使用bc
variable=$(echo "options; expression" | bc)
第一部分options允许你设置变量。如果你需要不止一个变量,可以用分号将其分开。expression参数定义了通过bc执行的数学表达式。
$ cat test9
#!/bin/bash
var1=$(echo "scale=4; 3.44 / 5" | bc)
echo The answer is $var1
$ chmod u+x test9
$ ./test9
The answer is .6880
退出脚本
shell中运行的每个命令都使用退出状态码(exit status)告诉shell它已经运行完毕。退出状态码是一个0~255的整数值,在命令结束运行时由命令传给shell。可以捕获这个值并在脚本中使用。Linux提供了一个专门的变量$?来保存上个已执行命令的退出状态码。
0 | 命令成功结束 | $ date Sat Jan 15 10:01:30 EDT 2014 $ echo $? 0 |
1 | 一般性未知错误(是给某个命令提供了无效参数) | $ date %t date: invalid date '%t' $ echo $? 1 $ |
2 | 不适合的shell命令 | |
126 | 命令不可执行(没有权限) | $ ./myprog.c -bash: ./myprog.c: Permission denied $ echo $? 126 $ |
127 | 没找到命令 | $ asdfg -bash: asdfg: command not found $ echo $? 127 |
128 | 无效的退出参数 | |
130 | 通过Ctrl+C终止的命令 | |
255 | 正常范围之外的退出状态码 |
默认情况下,shell脚本会以脚本中的最后一个命令的退出状态码退出。exit命令允许你在脚本结束时指定一个退出状态码。可以在exit命令的参数中使用变量.
$ cat test13
#!/bin/bash
# testing the exit status
var1=10
var2=30
var3=$[$var1 + $var2]
echo The answer is $var3
exit 5
$ chmod u+x test13
$ ./test13
The answer is 40
$ echo $?
5
$