## 第二章节 Shell脚本基本结构
2.1 脚本开头的Shebang(#!)行
2.2 变量定义与使用
变量是为其赋值的字符串。分配的值可以是数字、文本、文件名、设备或任何其他类型的数据。
变量不过是指向实际数据的指针。shell 可以让你创建、分配和删除变量
变量名称
变量名只能包含字母(a 至 z 或 A 至 Z)、数字(0 至 9)或下划线字符 ( _)。
按照惯例,Unix shell 变量的名称使用大写字母。
以下示例是有效的变量名
_ALI
TOKEN_A
VAR_1
VAR_2
AbbottSun
以下是无效的变量名称
2_VAR
-VARIABLE
VAR1-VAR2
VAR_A!
之所以不能使用 !、* 或 - 等其他字符,是因为这些字符对 shell 有特殊含义。
定义变量
变量定义如下
variable_name=variable_value
例如:
NAME="Zhang San"
上例定义了变量 NAME,并为其赋值 "Zhang San"。这种类型的变量称为标量变量。标量变量一次只能保存一个值。
shell 允许你在变量中存储任何你想要的值。例如:
VAR1="Zara Ali"
VAR2=100
访问值
要访问变量中存储的值,请在变量名前加上美元符号 ($) 。
例如,下面的脚本将访问已定义变量 NAME 的值,并将其打印出
#!/bin/sh
NAME="Zhang San"
echo $NAME
上述脚本将产生以下值:
Zhang San
只读变量
Shell 提供了一种使用只读命令将变量标记为只读的方法。变量被标记为只读后,其值将无法更改。
例如,下面的脚本在试图更改 NAME - 的值时会产生错误。
示例:
#!/bin/bash
NAME="Zara Ali"
readonly NAME
NAME="Qadiri"
输出结果:
read-Only-var.sh:行4: NAME: 只读变量
取消设置变量
取消设置或删除变量会指示 shell 从其跟踪的变量列表中删除该变量。一旦取消设置变量,就无法访问变量中存储的值。
使用 unset 命令取消已定义变量的语法如下
unset variable_name
上述命令将取消已定义变量的值。下面是一个简单的示例,演示该命令如何运行
#!/bin/sh
NAME="Zara Ali"
unset NAME
echo $NAME
上述示例不会打印任何内容。不能使用 unset 命令取消设置标记为只读的变量。
变量类型
shell 运行时,主要有三种变量类型
- 局部变量 - 局部变量是存在于 shell 当前实例中的变量。shell 启动的程序无法使用它。它们是在命令提示符下设置的。
- 环境变量 - shell 的任何子进程都可以使用环境变量。有些程序需要环境变量才能正常运行。通常,shell 脚本只定义其运行的程序所需的环境变量。
- shell 变量 - shell 变量是由 shell 设置的特殊变量,shell 需要它才能正常运行。其中一些变量是环境变量,而另一些则是本地变量。
特殊变量
在本章中,我们将详细讨论 Unix 中的特殊变量。在前面的一章中,我们了解了在变量名称中使用某些非字母数字字符时如何小心。这是因为这些字符被用在特殊 Unix 变量的名称中。这些变量是为特定功能保留的。
例如,$字符代表当前 shell 的进程 ID 号或 PID -
$echo $$
上面的命令写入当前 shell 的 PID -
29949
下表显示了您可以在 shell 脚本中使用的一些特殊变量 -
Number | 变量和描述 |
---|---|
1 | $0当前脚本的文件名。 |
2 | **$n**这些变量对应于调用脚本时使用的参数。这里**n**是一个正十进制数,对应于参数的位置(第一个参数是 $1,第二个参数是 $2,依此类推)。 |
3 | $#提供给脚本的参数数量。 |
4 | *$\***所有参数都用双引号引起来。如果脚本接收两个参数,$ 相当于 $1 $2。 |
5 | **$@**所有参数都单独用双引号引起来。如果脚本接收两个参数,$@ 相当于 $1 $2。 |
6 | $?最后执行的命令的退出状态。 |
7 | $$当前 shell 的进程号。对于 shell 脚本,这是执行它们的进程 ID。 |
8 | $!最后一个后台命令的进程号。 |
命令行参数
命令行参数 $1、$2、$3、...$9 是位置参数,$0 指向实际的命令、程序、shell 脚本或函数,$1、$2、$3、...$9 作为参数命令。
以下脚本使用与命令行相关的各种特殊变量 -
#!/bin/sh
echo "File Name: $0"
echo "First Parameter : $1"
echo "Second Parameter : $2"
echo "Quoted Values: $@"
echo "Quoted Values: $*"
echo "Total Number of Parameters : $#"
这是上述脚本的运行示例 -
$./test.sh Zara Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
特殊参数 $* 和 $@
有一些特殊参数允许一次访问所有命令行参数。$\***和**$@ 的作用相同,除非它们用双引号""括起来。
这两个参数都指定命令行参数。然而,“$*”特殊参数将整个列表作为一个参数,中间有空格,而“$@”特殊参数则将整个列表分为单独的参数。
我们可以编写如下所示的 shell 脚本来使用 $* 或 $@ 特殊参数处理未知数量的命令行参数 -
#!/bin/sh
for TOKEN in $*
do
echo $TOKEN
done
这是上述脚本的运行示例 -
$./test.sh Zara Ali 10 Years Old
Zara
Ali
10
Years
Old
注意- 这里do...done是一种循环,将在后续教程中介绍。
退出状态
美元?变量表示前一个命令的退出状态。
退出状态是每个命令完成后返回的数值。通常,大多数命令如果成功则返回退出状态 0,如果不成功则返回 1。
某些命令会出于特定原因返回其他退出状态。例如,某些命令区分不同类型的错误,并根据具体的故障类型返回各种退出值。
以下是成功命令的示例 -
$./test.sh Zara Ali
File Name : ./test.sh
First Parameter : Zara
Second Parameter : Ali
Quoted Values: Zara Ali
Quoted Values: Zara Ali
Total Number of Parameters : 2
$echo $?
0
$
2.3 基本的输入输出(读取用户输入、输出结果等)
在Shell编程中,你可以使用以下方式进行基本的输入和输出操作:
读取用户输入:
可以使用 read
命令来读取用户的输入,并将输入保存到一个变量中。例如:
read -p "请输入你的名字: " name
echo "你好,$name!"
上述代码将提示用户输入名字,并将输入保存到 name
变量中,然后通过 echo
命令输出一条问候语。
输出结果:
可以使用 echo
命令来输出文本或变量的值。例如:
name="John"
echo "你好,$name!"
上述代码将输出一条问候语,其中包含了变量 name
的值。
示例
1、多重输出(number.sh)
#!/bin/bash
read -p "Enter number one : " n1
read -p "Enter number two : " n2
read -p "Enter number three : " n3
echo "Number1 - $n1"
echo "Number2 - $n2"
echo "Number3 - $n3"
2、 显示域名所有者信息
显示互联网域名所有者信息的 shell 脚本 (domain.sh):
#!/bin/bash
read -t 10 -p "Enter the Internet domain name(sunshijz.cn) : " domain_name
whois $domain_name
输出结果:
Enter the Internet domain name(sunshijz.cn) : sunshijz.cn
Domain Name: sunshijz.cn
ROID: 20201130s10001s33110320-cn
Domain Status: ok
Registrant: 孙晓波
Registrant Contact Email: [email protected]
Sponsoring Registrar: 阿里巴巴云计算(北京)有限公司
Name Server: dns9.hichina.com
Name Server: dns10.hichina.com
Registration Time: 2020-11-30 16:48:57
Expiration Time: 2023-11-30 16:48:57
DNSSEC: unsigned
3、超时输入
使用 -t 选项可以使 read 命令超时。如果在 TIMEOUT 秒内没有读取完整的输入行,它将导致读取超时并返回失败。例如,如果在 10 秒内没有输入,程序将被中止(domain2.sh):
#!/bin/bash
read -t 10 -p "Enter the Internet domain name (sunshijz.cn) : " domain_name
whois $domain_name
4、隐藏密码
-s
选项会导致来自终端的输入不显示在屏幕上。这对处理密码(readpass.sh)非常有用:
#!/bin/bash
read -s -p "Enter Password : " my_password
echo
echo "Your password - $my_password"
处理多个值
示例1
read -p "Enter directory to delete : " dirname
echo "$dirname"
输出结果
Enter directory to delete : test bing /opt/test
test bing /opt/test
用户提供了三个值,而不是一个。现在字符串由三个不同的字段组成。所有三个字都将使用 $IFS 内部字段分隔符分配给 dirname。$IFS 决定了 shell 识别字段的方式。
$IFS
要显示 $IFS 的默认值,请输入
echo "$IFS"
您将看到一个空格,其中只有空格、制表符和换行符(默认值)
[root@bogon opt]# cat -etv <<<"$IFS"
^I$
$
$ - 行尾,即换行符
^I$ -制表符和换行符
但如何同时使用 $IFS 和 read 命令呢?
创建一个名为 nameservers 的变量,并赋予它以下 3 个值(注意所有值之间用空格隔开):
[root@bogon opt]# nameservers="ns1.nixcraft.net ns2.nixcraft.net ns3.nixcraft.net"
使用echo命令或printf命令显示变量nameservers的值:
[root@bogon opt]# echo "$nameservers"
or
[root@bogon opt]# printf "%s" $nameservers
现在,只需使用读取命令拆分 $nameservers
[root@bogon opt]# read -r ns1 ns2 ns3 <<< "$nameservers"
读取命令从 $nameservers 变量中读取输入值。
$IFS 的默认值用于为三个独立变量赋值。使用 $IFS 将输入内容分割成令牌,并分配给三个变量。
换句话说,IFS 变量起着标记分隔符或分隔线的作用。
第一个标记(ns1.nixcraft.net)保存为第一个变量的值($ns1)
第二个标记(ns2.nixcraft.net)保存为第二个变量的值($ns2)。
第三个标记(ns3.nixcraft.net)保存为第三个变量的值($ns3)。
要显示每个变量的值,请使用 echo 命令或 printf 命令,如下所示:
[root@bogon opt]# echo "dns sever1 $ns1"
dns sever1 ns1.nixcraft.net
[root@bogon opt]# echo "dns sever1 $ns2"
dns sever1 ns2.nixcraft.net
[root@bogon opt]# echo "dns sever1 $ns3"
dns sever1 ns3.nixcraft.net
or
[root@bogon opt]# printf "DNS Server #1 %s\n #2 %s\n #3 %s\n" $ns1 $ns2 $ns3
DNS Server #1 ns1.nixcraft.net
#2 ns2.nixcraft.net
#3 ns3.nixcraft.net
如何更改 IFS 分隔符值?
示例:
gitevivek:x:1002:1002::/home/gitevivek:/bin/sh
将上面一行内容赋值给一个名为 pwd 的变量:
pwd="gitevivek:x:1002:1002::/home/gitevivek:/bin/sh"
读取 $pwd,使用 $IFS 生成令牌并将其存储到相应字段:
read -r login password uid gid info home shell <<< "$pwd"
printf "Your login name is %s, uid %d, gid %d, home dir set to %s with %s as login shell\n" $login $uid $gid $home $shell
重定向输出:
使用 >
符号可以将命令的输出重定向到文件中,而不是终端。例如:
echo "Hello, World!" > output.txt
上述代码将输出文本 "Hello, World!" 并将其写入到 output.txt
文件中。
读取文件内容:
使用 cat
命令可以读取文件的内容,并将其输出到终端。例如:
cat file.txt
上述代码将读取 file.txt
文件的内容,并将其显示在终端上。
2.4 算术运算
您可以对 Bash shell 变量执行数学运算。Bash shell 有内置的算术选项。您也可以使用外部命令,如 expr 和 bc 计算器。
Bash Shell中的算术扩展
通过使用以下格式来放置整数表达式来进行算术扩展和计算:
$((expression))
$(( n1+n2 ))
$(( n1/n2 ))
$(( n1-n2 ))
示例:
使用 echo 命令将两个数字相加:
[root@bogon opt]# echo $(( 10 + 5 ))
15
使用 x 和 y 变量将两个数字相加。使用文本编辑器创建名为 add.sh 的 shell 程序:
#!/bin/bash
x=5
y=10
ans=$(( x + y ))
echo "$x + $y = $ans"
保存并关闭文件。按以下步骤运行:
chmod +x add.sh
./add.sh
输出结果
5 + 10 = 15
示例2:
使用 read 命令创建名为 add1.sh 的交互式程序:
#!/bin/bash
read -p "Enter two numbers : " x y
ans=$(( x + y ))
echo "$x + $y = $ans"
输出结果:
Enter two numbers : 20 30
20 + 30 = 50
带整数的数学运算符
运算符 | 描述 | 示例 | 求值结果 |
---|---|---|---|
+ | 加法 | echo $(( 20 + 5 )) | 25 |
- | 减法 | echo $(( 20 - 5 )) | 15 |
/ | 除法 | echo $(( 20 / 5 )) | 4 |
* | 乘法 | echo $(( 20 * 5 )) | 100 |
% | 取模 | echo $(( 20 % 3 )) | 2 |
++ | 自增 | x=5 echo $(( x++ )) echo $(( x++ )) | 5 6 |
-- | 自减 | x=5 echo $(( x-- )) | 4 |
** | 幂运算 | x=2 y=3 echo $(( x ** y )) | 8 |
优先级顺序
运算符按照优先级顺序进行评估。这些级别按照优先级递减的顺序列出(引用自bash手册页面)
评论 (0)