接上一篇文章Linux shell编程(五): Linux文件权限管理
三、Linux shell 脚本编程基础
了解了Linux系统和命令行的基础知识,是时候开始编程了。
3.1 基本shell脚本
shell脚本的关键在于输入多个命令并处理每个命令的结果,甚至需要将一个命令的结果传给另一个命令。如果要两个命令一起运行,可以把它们放在同一行中,彼此间用分号隔开,也就是前面讲过的命令列表,如下:
这就是一个shell脚本,但每次执行命令时都要重新输入这个语句,可以将它写到文本文件中,以后只要运行这个文件就行了,这就是shell脚本文件。
在创建shell脚本文件时,必须在文件的第一行指定要使用的shell版本,如下:
#!/bin/bash
whoami
date
可以仍然将 whoami
和 date
,放在一行并用分号隔开,也可以将他们独立成行,shell会按根据命令在文件中出现的顺序进行处理。
注:shell脚本的注释是以 #
开头的(指定shell版本以 #!
开头)
将上述shell脚本文件保存成名为shelltest的文件,并执行这个脚本文件,如下:
可以看到,显示找不到这个命令,前面讲过shell会通过 PATH
环境变量来查找命令,如果 PATH
环境变量里没有当前脚本文件所在路径,就会显示上述结果并尽可能给出可安装的推荐命令。要让shell可以找到脚本有多种方法:
- 在
PATH
环境变量中添加脚本文件所在的绝对路径; - 在
PATH
环境变量中添加./
路径; - 执行脚本时,使用脚本文件的绝对或相对路径。
这里使用方法3,使用相对路径执行脚本文件:
看到没有权限,这是因为Linux新建的文件默认没有执行权限,按照前面所讲的,使用 chmod u+x shelltest
命令为脚本文件添加执行权限即可:
所以,在执行shell脚本时,要注意到不仅要让shell可以找到脚本文件,还要保证当前执行脚本的用户对shell脚本文件有执行权限。
为更好地区分,常将bash shell文本文件保存为 .sh
后缀的文件,如 shelltest.sh
3.1.1 显示信息
就像c语言的 print()
函数一样,shell也有自己的输出方式 – echo
命令。
把要显示的内容放在 echo
后面即可,如下:
#!/bin/bash
echo hello world!
默认情况下,不需要使用引号将要显示的文本字符串划定出来。
但如果输出内容中有 '
或 "
等,则需要将输出内容用 ""
或 ''
括起来,否则输出会出现问题。
另外,echo
命令输出后默认在行尾加换行符,如果不希望换行,可以使用 -n
选项,如下:
echo "hello"
echo " world!"
----------------------
hello
world!
echo -n "hello"
echo " world!"
----------------------
hello world!
3.1.2 使用变量
既然是编程,就要有变量进行数据处理,前面讲过环境变量,可以理解为系统层面的全局变量,在脚本中可以访问这些值。
shell访问变量的语法为在变量名前加 $
符号,如下:
echo $HOME
----------------------
/home/vistar
也可以自定义变量,和大多数程序语言一样,shell程序变量的赋值也使用 =
,但 =
两端不允许有空格,这个原因在前面介绍过(shell语句的命令与参数是用空格分割的,shell会将变量名误认为是一条命令,然而它只是一个变量)。
另外,定义shell变量时,不需要指定数据类型,因为shell脚本会自动决定变量值的数据类型。
shell变量常见的用途是存储命令的输出内容,以便于对命令输出做各种处理。
有两种方法可以将命令输出赋给变量,也叫作 命令替换
:
# 反引号字符: `` (Tab键上面那个键)
date1=`date`
echo date1: $date1
# $()
date2=$(date)
echo date2: $date2
date
是shell编程中很一个有用的命令,详解见 Linux date 命令详解
3.1.3 输入重定向和输出重定向
有时需要将结果保存到文件或从文件导入数据,shell提供了重定向操作。
- 输入重定向:
<
和<<
- 输出重定向:
>
和>>
输出重定向
即将原本输出到屏幕的内容重定向输出到文件里,如下:
如果重定向的文件已经存在,则重定向内容会覆盖原来文件的内容,如果想在原来文件内容后面追加重定向内容,可以使用符号 >>
,如下:
输入重定向
将文件的内容重定向到命令,如 Linux shell编程(四): Linux 用户和组管理 讲到的批量修改用户密码,就是输入重定向:
sudo chpasswd < passwd.txt
还有另外一种输入重定向的方法,称为内联输入重定向(inline input redirection)。这种方法无需使用文件进行重定向,它可以读取交互shell中输入的数据,重定向到命令,内联输入重定向使用符号 <<
,如下:
其中,wc
是命令,它可以对数据中的文本进行计数,输出的三个值依次为:行数、次数、字节数。
<<
是内联重定向符号,end
是自定义的内联重定向结束标志,当读取到该标志时,内联重定向结束。
3.1.4 管道
前面介绍子shell时介绍过管道,它可以将一个命令的输出作为另一个命令的输入。如下:
不要以为由管道串起的两个命令会依次执行。Linux系统实际上会同时运行这两个命令,在系统内部将它们连接起来。在第一个命令产生输出的同时,输出会被立即送给第二个命令。数据传输不会用到任何中间文件或缓冲区。
3.1.5 数学运算
最开始的Bourne shell使用 expr
命令处理数学运算,但不是很好用,后来bash shell提供了更简单好用的方法,在将一个数学运算结果赋给某个变量时,用美元符和方括号 $[ operation ]
将数学表达式围起来,如下:
可以看到,c=8/6=1
,这是因为bash shell数学运算符只支持整数运算,看似是一个不幸的消息,怎么办呢,有一些解决方案,其中最常见的一种是 bash计算器
,叫作 bc
。
bc
允许在命令行中输入浮点表达式,然后解释并计算该表达式,最后返回结果。
bc
计算器能识别以下内容:
- 数字(整数和浮点数)
- 变量(简单变量和数组)
- 注释(以#开始的行或/* */包含的内容)
- 表达式
- 编程语句(例如if-then语句)
- 函数
可以在shell中运行 bc
:
输入数学计算式,回车即可输出结果,但 8/6
的结果仍然显示为 1
,这是因为 bc
计算浮点运算,默认小数位数为0,可以通过內建变量 scale
设置小数位数,如下:
可以看到,结果按照设置的小数位数显示了,输入 quit
退出 bc
。
bc
的 -q
选项可以不显示bash计算器冗长的欢迎信息,如下:
在脚本中使用 bc
需要借助前面介绍的 命令替换
和 管道
,格式如下:
variable=$(echo "options; expression" | bc)
其中,variable
是自定义的变量名,用以接收计算结果, options
是在 bc
的内置变量,多个变量用 ;
隔开,还有, expression
是计算表达式。
bc
有4个内置变量,
变量 | 描述 |
---|---|
scale | 指定精度,即小数点后的位数;默认为 0 |
ibase | 指定输入的数字的进制,默认为十进制 |
obase | 指定输出的数字的进制,默认为十进制 |
last/. | 表示最近打印的数字 |
计算时也可以使用脚本文件中已定义的变量,如下:
对于比较复杂的计算式,可以使用前面介绍的内联输入重定向方法:
在 bc
中也可以给变量赋值,但在 bc
中创建的变量只在 bc
中有效,不能在shell脚本中使用。
3.1.6 退出脚本
shell中运行的每个命令都使用退出状态码告诉shell它已经运行完毕。退出状态码是一个0~255的整数值,在命令结束运行时由命令传给shell。可以捕获这个值并在脚本中使用。
Linux提供了一个专门的变量 $?
来保存上个已执行命令的退出状态码。一个成功结束的命令的退出状态码是 0 。如果一个命令结束时有错误,退出状态码就是一个正值。无效命令会返回一个退出状态码 127 。
一些退出状态码如下:
状态码 | 描述 |
---|---|
0 | 命令成功结束 |
1 | 未知错误(参数无效等) |
2 | 不适合的shell命令 |
126 | 命令不可执行(无权限) |
127 | 没找到命令 |
128 | 无效的退出参数 |
128+x | 与Linux信号x相关的严重错误 |
130 | 通过Ctrl+C终止的命令 |
255 | 正常范围之外的退出状态码 |
默认情况下,shell脚本会以脚本中的最后一个命令的退出状态码退出,也可以使用 exit
命令为自己的脚本指定退出状态码。如下:
也可以使用变量作为 exit
命令的参数,
但自定义状态码也必须在0-255范围内,否则状态码会以原状态码对256取模作为结果,如下:
自定义的状态码是 300
,结果输出的是 44
,300%256
的结果是 44
。