本章内容:
- 使用多个命令
- 创建脚本文件
- 显示消息
- 使用变量
- 重定向输入和输出
- 管道
- 数学运算
- 退出脚本
shell 可以将多个命令串联起来,一次性执行完。
# 1.date命令显示当前日期和时间,whoami显示当前登录用户名。
[root@VM-8-11-centos ~]# date ; whoami
Tue Jun 6 21:09:11 CST 2023
root
要将 shell 命令放到文本文件中,首先要用文本编辑器创建一个文件,然后在其中输入命令。
#!/bin/bash
# 1.编辑脚本。
[root@VM-8-11-centos testdir]# vim test.sh
# 2.脚本内容。
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
date
whoami
# 3.尝试执行脚本。(提示无执行权限)
[root@VM-8-11-centos testdir]# ./test.sh
-bash: ./test.sh: Permission denied
# 4.查看权限。
[root@VM-8-11-centos testdir]# ls -l test.sh
-rw-r--r-- 1 root shared 24 Jun 6 22:13 test.sh
# 5.为当前用户添加可执行权限。
[root@VM-8-11-centos testdir]# chmod u+x test.sh
[root@VM-8-11-centos testdir]# ls -l test.sh
-rwxr--r-- 1 root shared 24 Jun 6 22:13 test.sh
# 6.成功执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
Tue Jun 6 22:15:34 CST 2023
root
很多时候,你可能想添加自己的文本消息来告诉用户脚本正在做什么,可以通过
echo
命令来实现这一点。它是 shell 脚本中同用户交互的重要工具,会经常用它来显示脚本中变量的值。
# 1.脚本内容。(追加echo显示)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
date
echo "=========="
whoami
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
Wed Jun 7 21:54:02 CST 2023
==========
root
变量允许在 shell 脚本中临时存储信息,以便同脚本中的其他命令一起使用。
shell 维护着一组用于记录特定的系统信息的环境变量,比如系统名称、已登录系统的用户名、用户的系统ID(也称 UID)、用户的默认主目录以及 shell 查找程序的搜索路径。
set
或者 printenv
命令查看环境变量。# 1.脚本内容。(显示环境变量)
[root@VM-8-11-centos testdir]# cat test01.sh
#!/bin/bash
echo "USER=$USER"
echo "UID=$UID"
echo "HOME=$HOME"
# 2.执行脚本。(成功引用环境变量)
[root@VM-8-11-centos testdir]# ./test01.sh
USER=root
UID=0
HOME=/root
[root@VM-8-11-centos testdir]# echo "cost $15"
cost 5
# 1.加上反斜线进行转义。
[root@VM-8-11-centos testdir]# echo "cost \$15"
cost $15
除了环境变量,shell 脚本还允许用户在脚本中定义和使用自己的变量。定义变量允许在脚本中临时存储并使用数据,从而使 shell 脚本看起来更像一个真正的计算机程序。
用户自定义变量的名称可以是任何由字母、数字或下划线组成的字符串,长度不能超过 20 个字符。
变量名区分大小写。
使用等号为变量赋值。(在变量、等号和值之间不能出现空格!)
脚本会以字符串的形式存储所有的变量值,脚本中的各个命令可以自行决定变量值的数据类型。
脚本中定义的变量在脚本的整个生命周期里会一直保持着它们的值,在脚本结束时会被删除。
与系统变量类似,用户自定义变量可以通过 $ 引用。
应用示例:
# 1.脚本内容。(自定义变量并使用)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
my_var="hello world!"
echo $my_var
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
hello world!
shell 脚本中最有用的特性之一是可以从命令输出中提取信息并将其赋值给变量。把输出赋给变量之后,就可以随意在脚本中使用了。在脚本中处理数据时,这个特性显得尤为方便。
# 1.脚本内容。(分别使用两种方法,将命令输出赋值给变量)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
user1=`whoami`
echo "$user1"
user2=$(whoami)
echo "$user2"
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
root
root
有时候,你想要保存命令的输出而不只是在屏幕上显示。bash shell 提供了几个运算符,它们可以将命令的输出重定向到其他位置(比如文件)。重定向既可用于输入,也可以用于输出。
最基本的重定向会将命令的输出发送至文件。
# 1.输出重定向。
[root@VM-8-11-centos testdir]# whoami > test01.txt
[root@VM-8-11-centos testdir]# cat test01.txt
root
# 2.再次重定向到相同文件。(覆盖)
[root@VM-8-11-centos testdir]# date > test01.txt
[root@VM-8-11-centos testdir]# cat test01.txt
Fri Jun 9 16:03:28 CST 2023
# 1.原文件内容。
[root@VM-8-11-centos testdir]# cat test01.txt
Fri Jun 9 16:14:13 CST 2023
# 2.追加新的数据内容。
[root@VM-8-11-centos testdir]# whoami >> test01.txt
[root@VM-8-11-centos testdir]# cat test01.txt
Fri Jun 9 16:14:13 CST 2023
root
输入重定向和输出重定向正好相反。输入重定向会将文件的内容重定向至命令。
# 1.文件内容。
[root@VM-8-11-centos testdir]# cat test01.txt
Fri Jun 9 16:14:13 CST 2023
root
# 2.使用wc命令对文本内容进行统计。(输出信息分别为:行数、单词数、字节数。)
[root@VM-8-11-centos testdir]# wc < test01.txt
2 7 34
# 1.EOF命令是END Of File的缩写,表示自定义终止符。(划分输入数据的起止)
# 2.wc命令对输入内容进行统计。(输出信息分别为:行数、单词数、字节数。)
[root@VM-8-11-centos testdir]# wc << EOF
> hello world
> aaa
> bbb
> EOF
3 4 20
无须将命令输出重定向至文件,可以将其直接传给另一个命令。这个过程称为管道连接( piping )
管道操作符由两个竖线组成,一个在上,一个在下。然而,其印刷体往往看起来更像是单个竖线( | )。
管道被置于命令之间,将一个命令的输出传入另一个命令。
可别以为由管道串联起来的两个命令会依次执行。实际上,Linux 系统会同时运行这两个命令,在系统内部将二者连接起来。
管道操作是实时化的,并且数据传输不会用到任何中间文件或缓冲区。
管道可以串联的命令数量没有限制。可以持续地将命令输出通过管道传给其他命令来细化操作。
应用示例:
# 1.rpm -qa显示已安装包的列表,再查找包名含有"python3"的包并对其排序显示。
[root@VM-8-11-centos testdir]# rpm -qa | grep "python3" | sort
python3-3.6.8-18.el7.x86_64
python3-libs-3.6.8-18.el7.x86_64
python3-pip-9.0.3-8.el7.noarch
python3-setuptools-39.2.0-10.el7.noarch
more
命令。在 shell 脚本中,执行数学运算有两种方式。
expr
命令可在命令行中执行数学运算,用于在 Unix / Linux 下求表达式变量的值,一般用于整数值,也可用于字符串。
expr
命令运算符在 shell 中另有他意( 比如 * ),所以要用反斜杠( \ ) 放在 shell 特定的字符前面;# 1.整数运算。(使用乘号时,必须用反斜线屏蔽其特定含义,因为shell可能会误解显示星号的意义。)
[root@VM-8-11-centos ~]# expr 30 \* 3
90
# 2.计算字符串长度。
[root@VM-8-11-centos ~]# expr length "hello world"
11
在 bash 中,要将数学运算结果赋给变量,可以使用 $ 和 方括号( $[ operation ] )。
# 1.脚本内容。
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
var1=$[1 + 5]
echo "1+5=$var1"
num1=10
num2=20
var2=$[$num1 * ($num2 - $num1)]
echo "10*(20-10)=$var2"
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
1+5=6
10*(20-10)=100
# 1.脚本内容。(整数相除)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=100
num2=45
var1=$[$num1 / $num2]
echo "100/45=$var1"
# 2.计算结果精度丢失。
[root@VM-8-11-centos testdir]# ./test.sh
100/45=2
有几种解决方案能够克服 bash 只支持整数运算的限制。最常见的做法是使用内建的 bash 计算器
bc
。
# 1.bc命令访问bash计算器。(要退出计算器必须输入quit)
[root@VM-8-11-centos testdir]# 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 * 5
60
0.1 * (1 + 9)
1.0
quit
# 2.-q选项表示不显示冗长的欢迎信息,通过scale变量设置保留的小数位数。
[root@VM-8-11-centos testdir]# bc -q
3.44 / 5
0
scale=4
3.44 / 5
.6880
quit
bc
命令,将输出赋给变量,基本格式为: variable=$(echo
“option; expression” | bc
)。# 1.脚本内容。(通过命令替换运行bc计算器)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=100
num2=45
var1=$(echo "scale=4; $num1 / $num2" | bc)
echo "100/45=$var1"
# 2.执行脚本。(小数保留4位。)
[root@VM-8-11-centos testdir]# ./test.sh
100/45=2.2222
# 1.使用内联重定向。(不通过表达式格式进行计算)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=100
num2=45
var1=$(bc << EOF
scale = 4
$num1 / $num2
EOF
)
echo "100/45=$var1"
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
100/45=2.2222
shell 中运行的每个命令都使用退出状态码来告诉 shell 自己已经运行完毕。退出状态码是一个 0 ~ 255 的整数值,在命令结束运行时由其传给 shell。你可以获取这个值并在脚本中使用。
Linux 提供了专门的变量 $? 来保存最后一个已执行命令的退出状态码。对于需要进行检查的命令,必须在其运行完毕后立刻查看或使用 $? 变量。这是因为该变量的值会随时变成由 shell 执行的最后一个命令的退出状态码。
状态码 | 描述 |
---|---|
0 | 命令成功结束。 |
1 | 一般性未知错误。 |
2 | 不适合的 shell 命令。 |
126 | 命令无法执行。 |
127 | 没找到命令。 |
128 | 无效的退出参数。 |
128+x | 与 Linux 信号 x 相关的严重错误。 |
130 | 通过 Ctrl + C 终止的命令。 |
255 | 正常范围之外的退出状态码。 |
# 1.查看文件权限。
[root@VM-8-11-centos testdir]# ls -l 1.sh
-rw-r--r-- 1 root shared 0 Jun 10 06:47 1.sh
# 2.无执行权限。
[root@VM-8-11-centos testdir]# ./1.sh
-bash: ./1.sh: Permission denied
# 3.状态码为126。
[root@VM-8-11-centos testdir]# echo $?
126
在默认情况下,shell 脚本会以脚本中的最后一个命令的退出状态码退出。而
exit
命令允许在脚本结束时指定一个退出状态码。
# 1.脚本内容。(指定退出状态码)
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=100
num2=45
var1=$[$num1 + $num2]
echo "100+45=$var1"
exit 7
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
100+45=145
# 3.成功使用指定的退出状态码。
[root@VM-8-11-centos testdir]# echo $?
7
exit
命令的参数。# 1.变量赋值给状态码。
[root@VM-8-11-centos testdir]# cat test.sh
#!/bin/bash
num1=10
num2=30
var1=$[$num1 * $num2]
echo "10*30=$var1"
exit $var1
# 2.执行脚本。
[root@VM-8-11-centos testdir]# ./test.sh
10*30=300
# 3.状态码数值被缩减。
[root@VM-8-11-centos testdir]# echo $?
44
“-------怕什么真理无穷,进一寸有一寸的欢喜。”
微信公众号搜索:饺子泡牛奶。