第二章节 Shell脚本基本结构

admin
2024-01-25 / 0 评论 / 67 阅读 / 正在检测是否收录...

shell-logo-black-and-white-4.png## 第二章节 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

评论 (0)

取消