2025-02-07
编程
00
请注意,本文编写于 79 天前,最后修改于 79 天前,其中某些信息可能已经过时。

目录

1.脚本头部
2.运行 Shell 脚本
2.1 作为可执行程序
2.2 作为解释器参数
2.3 输出变量echo print test
3. Shell变量
3.1 变量赋值
3.2 使用变量
3.3 只读变量 readonly
3.4 删除变量 unset
3.6 Shell 传递参数
4.字符串(单引号与双引号)
5.数组
5.1定义数组
5.2读取数组
5.3 定义关联数组(字典)
5.3 使用关联数组(字典)
6.运算符
6.1 算数运算符
6.2 关系运算符
6.3 布尔运算符
6.4 逻辑运算符
6.5 字符串运算符
7.流程控制
7.1 if 语句
7.1.1 if 单分支语句语法格式:
7.1.2 if 多分支语句语法格式:
7.2 for 循环
7.3 while 语句
7.4 until 循环
7.5 case ... esac
7.6 跳出循环
7.6.1 break
7.6.2 continue
8.函数
8.1 无参函数
8.2 有参函数
8.3 函数的特殊参数(补充)
9.重定向
9.1 重定向基本
9.2 重定向深入讲解
9.3 Here Document 写入文本
9.4 /dev/null 文件
10.文件包含
10.1 调用文件
10.2 实例
11.test命令

shell脚本编写

1.脚本头部

#!/bin/bash

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell

2.运行 Shell 脚本

2.1 作为可执行程序

将上面的代码保存为 test.sh,并 cd 到相应目录:

chmod +x ./test.sh #使脚本具有执行权限 ./test.sh #执行脚本

注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

2.2 作为解释器参数

这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:

/bin/sh test.sh /bin/python test.py

2.3 输出变量echo print test

输出变量有三种方法echo print test

#输出变量 echo "hello" #输出变量(printf 不会像 echo 自动添加换行符,我们可以手动添加 \n。) printf "hello" #test 检查条件是否成立 num1=100 num2=100 if test $[num1] -eq $[num2] then echo '两个数相等!' else echo '两个数不相等!' fi

3. Shell变量

3.1 变量赋值

等号两侧避免使用空格,正确的赋值

variable_name=value

有可能会导致错误

variable_name = value

除了显式地直接赋值,还可以用语句给变量赋值,如:

for file in `ls /etc` 或 for file in $(ls /etc)

以上语句将 /etc 下目录的文件名循环出来。

3.2 使用变量

your_name="tom" echo $your_name your_name="alibaba" echo $your_name

3.3 只读变量 readonly

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
下面的例子尝试更改只读变量,结果报错:

#!/bin/bash myUrl="https://www.google.com" readonly myUrl myUrl="https://www.runoob.com"

3.4 删除变量 unset

使用 unset 命令可以删除变量。语法:

unset variable_name

变量被删除后不能再次使用。unset 命令不能删除只读变量

3.5 特殊变量 00 1 # ?

有一些特殊变量在 Shell 中具有特殊含义,例如:

$0 表示脚本的名称 $1, $2, 等表示脚本的参数。 $#表示传递给脚本的参数数量 $? 表示上一个命令的退出状态等。

3.6 Shell 传递参数

我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:nn代表一个数字,1为执行脚本的第一个参数,2为执行脚本的第二个参数,以此类推</br>以下实例我们向脚本传递三个参数,并分别输出,其中n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……</br> 以下实例我们向脚本传递三个参数,并分别输出,其中 0 为执行的文件名:

#!/bin/bash # author:W3Cschool教程 # url:www.w3cschool.cn echo "Shell 传递参数实例!"; echo "执行的文件名:$0"; echo "第一个参数为:$1"; echo "第二个参数为:$2"; echo "第三个参数为:$3";

为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh $ ./test.sh 1 2 3 Shell 传递参数实例! 执行的文件名:test.sh 第一个参数为:1 第二个参数为:2 第三个参数为:3

另外,还有几个特殊字符用来处理参数:

$# 传递到脚本的参数个数 $* 以一个单字符串显示所有向脚本传递的参数。如"$*"用「"」括起来的情况、以"$1 $2 … $n"的形式输出所有参数。 $$ 脚本运行的当前进程ID号 $! 后台运行的最后一个进程的ID号 $@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。 $- 显示Shell使用的当前选项,与set命令功能相同。 $? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
#!/bin/bash # author:W3Cschool教程 # url:www.w3cschool.cn echo "Shell 传递参数实例!"; echo "第一个参数为:$1"; echo "参数个数为:$#"; echo "传递的参数作为一个字符串显示:$*";

执行脚本,输出结果如下所示:

$ chmod +x test.sh $ ./test.sh 1 2 3 Shell 传递参数实例! 第一个参数为:1 参数个数为:3 传递的参数作为一个字符串显示:1 2 3

执行脚本,输出结果如下所示:

$ chmod +x test.sh $ ./test.sh 1 2 3 Shell 传递参数实例! 第一个参数为:1 参数个数为:3 传递的参数作为一个字符串显示:1 2 3

* 与 @ 区别:
● 相同点:都是引用所有参数。
● 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。

#!/bin/bash echo "-- \$* 演示 ---" for i in "$*"; do echo $i done echo "-- \$@ 演示 ---" for i in "$@"; do echo $i done

执行脚本,输出结果如下所示:

$ chmod +x test.sh $ ./test.sh 1 2 3 -- $* 演示 --- 1 2 3 -- $@ 演示 --- 1 2 3

4.字符串(单引号与双引号)

引号字符串的限制:
● 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
● 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用
双引号的优点:
● 双引号里可以有变量
● 双引号里可以出现转义字符

5.数组

5.1定义数组

# 第一种方法 array_name=(value1 value2 ... valuen) # 第二种方法 array_name[0]=value0 array_name[1]=value1 array_name[2]=value2

5.2读取数组

${array_name[index]}

5.3 定义关联数组(字典)

#第一种方法创建关联数组 declare -A site=(["google"]="www.google.com" ["runoob"]="www.runoob.com" ["taobao"]="www.taobao.com") #第二种方法创建关联数组 declare -A site site["google"]="www.google.com" site["runoob"]="www.runoob.com" site["taobao"]="www.taobao.com"

5.3 使用关联数组(字典)

#第一种使用方法,用下标 ${array_name[index]} #第一种使用方法,用索引 ${site["runoob"]} #使用 @ 或 * 可以获取数组中的所有元素 echo "数组的元素为: ${my_array[*]}" echo "数组的元素为: ${my_array[@]}"

6.运算符

6.1 算数运算符

完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边 + 加法 `expr $a + $b` 结果为 30。 - 减法 `expr $a - $b` 结果为 -10。 * 乘法 `expr $a \* $b` 结果为 200。 / 除法 `expr $b / $a` 结果为 2。 % 取余 `expr $b % $a` 结果为 0。 = 赋值 a=$b 把变量 b 的值赋给 a。 == 相等。用于比较两个数字,相同则返回 true。 [ $a == $b ] 返回 false。 != 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 返回 true。 注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]

6.2 关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。 下表列出了常用的关系运算符,假定变量 a 为 10,变量 b 为 20:

运算符 说明 举例 -eq 检测两个数是否相等,相等返回 true。 [ $a -eq $b ] 返回 false。 -ne 检测两个数是否不相等,不相等返回 true。 [ $a -ne $b ] 返回 true。 -gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ $a -gt $b ] 返回 false。 -lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ $a -lt $b ] 返回 true。 -ge 检测左边的数是否大于等于右边的,如果是,则返回 true。 [ $a -ge $b ] 返回 false。 -le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ $a != $b ] 返回 true。

6.3 布尔运算符

下表列出了常用的布尔运算符,假定变量 a 为 10,变量 b 为 20:

运算符 说明 举例 ! 非运算,表达式为 true 则返回 false,否则返回 true。 [ ! false ] 返回 true。 -o 或运算,有一个表达式为 true 则返回 true。 [ $a -lt 20 -o $b -gt 100 ] 返回true。 -a 与运算,两个表达式都为 true 才返回 true。 [ $a -lt 20 -a $b -gt 100 ] 返回 false。

6.4 逻辑运算符

运算符 说明 举例 && 逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false || 逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true

6.5 字符串运算符

下表列出了常用的字符串运算符,假定变量 a 为 "abc",变量 b 为 "efg":

运算符 说明 举例 = 检测两个字符串是否相等,相等返回 true。 [ $a = $b ] 返回 false。 != 检测两个字符串是否不相等,不相等返回 true。 [ $a != $b ] 返回 true。 -z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false。 -n 检测字符串长度是否不为 0,不为 0 返回 true。 [ -n "$a" ] 返回 true。 $ 检测字符串是否不为空,不为空返回 true。 [ $a ] 返回 true。

7.流程控制

7.1 if 语句

7.1.1 if 单分支语句语法格式:

if condition then command1 command2 ... commandN else command fi

7.1.2 if 多分支语句语法格式:

if condition1 then command1 elif condition2 then command2 else commandN fi

注意:

if else 的 [...] 判断语句中大于使用 -gt,小于使用 -lt。 if [ "$a" -gt "$b" ]; then ... fi 如果使用 ((...)) 作为判断语句,大于和小于可以直接使用 > 和 <。 if (( a > b )); then ... fi

7.2 for 循环

for loop in 1 2 3 4 5 do echo "The value is: $loop" done

7.3 while 语句

#!/bin/bash int=1 while(( $int<=5 )) do echo $int let "int++" done

7.4 until 循环

until 循环执行一系列命令直至条件为 true 时停止,until 循环与 while 循环在处理方式上刚好相反。

#!/bin/bash a=0 until [ ! $a -lt 10 ] do echo $a a=`expr $a + 1` done

7.5 case ... esac

case ... esac 为多选择语句,与其他语言中的 switch ... case 语句类似,是一种多分支选择结构,每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句,esac(就是 case 反过来)作为结束标记。 可以用 case 语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

case ... esac 语法格式如下: echo '输入 1 到 4 之间的数字:' echo '你输入的数字为:' read aNum case $aNum in 1) echo '你选择了 1' ;; 2) echo '你选择了 2' ;; 3) echo '你选择了 3' ;; 4) echo '你选择了 4' ;; *) echo '你没有输入 1 到 4 之间的数字' ;; esac

7.6 跳出循环

7.6.1 break

7.6.2 continue

8.函数

8.1 无参函数

#!/bin/bash demoFun(){ echo "这是我的第一个 shell 函数!" } echo "-----函数开始执行-----" demoFun echo "-----函数执行完毕-----"

8.2 有参函数

#!/bin/bash funWithParam(){ echo "第一个参数为 $1 !" echo "第二个参数为 $2 !" echo "第十个参数为 $10 !" echo "第十个参数为 ${10} !" echo "第十一个参数为 ${11} !" echo "参数总数有 $# 个!" echo "作为一个字符串输出所有参数 $* !" } funWithParam 1 2 3 4 5 6 7 8 9 34 73

8.3 函数的特殊参数(补充)

另外,还有几个特殊字符用来处理参数:

参数处理 说明 $# 传递到脚本或函数的参数个数 $* 以一个单字符串显示所有向脚本传递的参数 $$ 脚本运行的当前进程ID号 $! 后台运行的最后一个进程的ID号 $@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。 $- 显示Shell使用的当前选项,与set命令功能相同。 $? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。

9.重定向

9.1 重定向基本

命令 说明 command > file 将输出重定向到 file。 command < file 将输入重定向到 file。 command >> file 将输出以追加的方式重定向到 file。 n > file 将文件描述符为 n 的文件重定向到 file。 n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。 n >& m 将输出文件 m 和 n 合并。 n <& m 将输入文件 m 和 n 合并。 << tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。

9.2 重定向深入讲解

一般情况下,每个 Unix/Linux 命令运行时都会打开三个文件: ● 标准输入文件(stdin):stdin的文件描述符为0,Unix程序默认从stdin读取数据。
● 标准输出文件(stdout):stdout 的文件描述符为1,Unix程序默认向stdout输出数据。
● 标准错误文件(stderr):stderr的文件描述符为2,Unix程序会向stderr流中写入错误信息。
默认情况下,command > file 将 stdout 重定向到 file,command < file 将stdin 重定向到 file。
如果希望 stderr 重定向到 file,可以这样写:

$ command 2>file

如果希望 stderr 追加到 file 文件末尾,可以这样写:

$ command 2>>file

2 表示标准错误文件(stderr)
如果希望将 stdout 和 stderr 合并后重定向到 file,可以这样写:

$ command > file 2>&1

或者

$ command >> file 2>&1

如果希望对 stdin 和 stdout 都重定向,可以这样写:

$ command < file1 >file2

command 命令将 stdin 重定向到 file1,将 stdout 重定向到 file2。

9.3 Here Document 写入文本

Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。它的基本的形式如下:

command << delimiter document delimiter

它的作用是将两个 delimiter 之间的内容(document) 作为输入传递给 command。

$ wc -l << EOF 欢迎来到 www.baidu.com EOF

9.4 /dev/null 文件

如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:

$ command > /dev/null

/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃;如果尝试从该文件读取内容,那么什么也读不到。但是 /dev/null 文件非常有用,将命令的输出重定向到它,会起到"禁止输出"的效果。 如果希望屏蔽 stdout 和 stderr,可以这样写:

$ command > /dev/null 2>&1

注意:0 是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。 这里的 2 和 > 之间不可以有空格,2> 是一体的时候才表示错误输出。

10.文件包含

和其他语言一样,Shell 也可以包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件

10.1 调用文件

. filename
注意点号(.)和文件名中间有一空格 或 source filename

10.2 实例

创建两个 shell 脚本文件。

test1.sh 代码如下: #!/bin/bash url="http://www.baidu.com"

test2.sh 代码如下:

#!/bin/bash #使用 . 号来引用test1.sh 文件 . ./test1.sh # 或者使用以下包含文件代码 # source ./test1.sh echo "官网地址:$url"

接下来,我们为 test2.sh 添加可执行权限并执行:

$ chmod +x test2.sh $ ./test2.sh

11.test命令

2022-07-19 16:17 更新 Shell中的 test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

数值测试 参数 说明 -eq 等于则为真 -ne 不等于则为真 -gt 大于则为真 -ge 大于等于则为真 -lt 小于则为真 -le 小于等于则为真

实例演示:

num1=100 num2=100 if test $[num1] -eq $[num2] then echo '两个数相等!' else echo '两个数不相等!' fi

输出结果:

两个数相等! 字符串测试 参数 说明 = 等于则为真 != 不相等则为真 -z 字符串 字符串长度为零则为真 -n 字符串 字符串长度不为零则为真

实例演示:

num1="W3Cschool" num2="W3Cschool" if test num1=num2 then echo '两个字符串相等!' else echo '两个字符串不相等!' fi

输出结果: 两个字符串相等!

文件测试

参数 说明 -e 文件名 如果文件存在则为真 -r 文件名 如果文件存在且可读则为真 -w 文件名 如果文件存在且可写则为真 -x 文件名 如果文件存在且可执行则为真 -s 文件名 如果文件存在且至少有一个字符则为真 -d 文件名 如果文件存在且为目录则为真 -f 文件名 如果文件存在且为普通文件则为真 -c 文件名 如果文件存在且为字符型特殊文件则为真 -b 文件名 如果文件存在且为块特殊文件则为真

实例演示:

cd /bin if test -e ./bash then echo '文件已存在!' else echo '文件不存在!' fi 输出结果: 文件已存在!

另外,Shell还提供了与( -a )、或( -o )、非( ! )三个逻辑操作符用于将测试条件连接起来,其优先级为:"!"最高,"-a"次之,"-o"最低。例如:

cd /bin if test -e ./notFile -o -e ./bash then echo '有一个文件存在!' else echo '两个文件都不存在' fi 输出结果: 有一个文件存在!

文章如有错误,还望留言指正

参考资料
https://www.runoob.com/linux/linux-shell.html