【语言类】“最全”Shell脚本编程梳理,从入门到精通

参考资料:

Linux 命令大全 | 菜鸟教程

Shell 教程 | 菜鸟教程

Shell编程入门学习_shell脚本编写_小达学加瓦的博客-CSDN博客

shell 脚本编写使用_shell脚本编写_行稳方能走远的博客-CSDN博客

一、shell 脚本的概念

        通俗地,shell脚本将终端中连续输入并执行的命令写成一个文件,然后直接运行该文件,shell脚本提供数组、循环、条件判断等功能。

        shell是一个用户和操作系统之间的命令行解释器,为用户提供一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可用shell来启动、挂起、停止甚至编写一些程序。

        shell本身也是C语言编写的。嵌入式板子启动内核后,首先启动Shell控制台,执行各种脚本,最后执行需要我们经常维护的rcS(就是 Shell)脚本:创建设备节点、挂载分区、安装驱动、启动主程序

1.1 sh和bash区别

1.2 Linux 的 Shell 种类

Linux 的 Shell 种类众多,常见的有:

  • Bourne Shell(/usr/bin/sh或/bin/sh)
  • Bourne Again Shell(/bin/bash)
  • C Shell(/usr/bin/csh)
  • K Shell(/usr/bin/ksh)
  • Shell for Root(/sbin/sh)

1.3 shell中特殊符号

符号

作用

' '

单引号。在单引号中所有的特殊符号,如“$”和”(反引号)都没有特殊含义。单引号括起来的都是普通字符,会原样输出

" "

双引号。在双引号中特殊符号都没有特殊含义,但是“$”,“`”(esc键下面)和“\”是例外,拥有“调用变量的值”、“引用命令”和“转义符”的特殊含义。

` `

反引号。反引号括起来的内容是系统命令,在Bash中会先执行它。和( ) 作 用 一 样 , 不 过 推 荐 使 用 ()作用一样,不过推荐使用()作用一样,不过推荐使用(),因为反引号非常容易看错。

$()

和反引号作用一样,用来引用系统命令。(推荐使用)

()

用于一串命令执行时,()中的命令会在子Shell中运行

{}

用于一串命令执行时,{ }中的命令会在当前Shell中执行。也可以用于变量变形与替换。

[ ]

用于变量的测试。

#

在Shell脚本中,#开头的行代表注释。

$

用于调用变量的值,如需要调用变量name的值时,需要用$name的方式得到变量的值。

\

转义符,跟在\之后的特殊符号将失去特殊含义,变为普通字符。如$将输出“$”符号,而不当做是变量引用。

二、shell脚本执行方式

shell脚本是一个纯文本文件,命令自上往下逐行执行。

2.1 shell脚本拓展名为.sh。

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

#!/bin/sh    或者  #!/bin/bash

2.2 脚本需要有可执行权限

chmod 777 first.sh
或者
chmod +x ./first.sh

2.3 脚本常用执行方式

  • 方式1(输入脚本的绝对路径或相对路径
    • 首先要赋予.sh脚本的+x权限
    • 执行脚本

                

                

  • 方式2(sh+脚本

        说明:不用赋予脚本+x权限,直接执行即可

        

三、shell编程

3.1 shell变量介绍

  1. Linux shell变量分为系统变量和用户自定义变量。
  2. 系统变量:HOME、PWD、SHELL、USER等,比如echo $HOME
  3. 显示当前shell中所有变量:set

​        

        

3.2 shell变量类型

3.2.1 基本语法

  1. 定义变量:变量=值(不能有空格
  2. 删除变量:unset 变量
  3. 声明静态变量:readonly变量,注意:不能unset

      ​​​​​​ 

        (1)错误,变量赋值不能有空格

       

        (2)错误,readonly变量不能使用unset

3.2.1.1 定义变量的规则
  1. 变量名称可以由字母、数字和下划线组成,但首个字符不能以数字开头。
  2. 等号两侧不能有空格
  3. 变量名称一般为大写
  4. 不能使用标点符号
3.2.1.2 将命令的返回值赋给变量
  1. A=`ls -la` 反引号,运行里面的命令,并把结果返回给变量A
  2. A=$(ls-la)等价于反引号

      

注:变量名外面最好加上花括号{},为了版主解释器识别变量的边界

for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done

3.2.2 环境变量

基本语法

  1. export 变量名=变量值 (功能描述:将shell变量输出为环境变量)
  2. source 配置文件 (功能描述:让修改后的配置信息立即生效)
  3. echo $变量名 (功能描述:查询环境变量的值)
#Shell常见的变量之二环境变量,主要是在程序运行时需要设置,环境变量详解如下:

PATH  		命令所示路径,以冒号为分割;
HOME  		打印用户家目录;
SHELL 		显示当前Shell类型;
USER  		打印当前用户名;
ID    		打印当前用户id信息;
PWD   		显示当前所在路径;
TERM  		打印当前终端类型;
HOSTNAME    显示当前主机名;
PS1         定义主机命令提示符的;
HISTSIZE    历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间;
RANDOM      随机生成一个 0 至 32767 的整数;
HOSTNAME    主机名

3.2.3 特殊变量

3.2.3.1 位置参数变量

用途介绍

        在执行一个shell脚本时,如果希望获取到命令行的参数信息,就可使用到位置参数变量

例:./myshell.sh 100 200 #执行shell的命令行,可在myshell脚本中获取到参数信息

基本语法

命令

功能描述

$0

当前脚本的文件名

$n

n为整数,$0代表命令本身,$1-9代表第1到第9个参数,10以上的参数需要用大括号包含,如${10}

$*

以一个单字符串显示所有向脚本传递的参数,$*把所有的参数看成一个整体

$@

命令行中所有的参数,$@把每个参数区分对待

$#

命令行中参数的个数(传递给脚本或函数的参数个数)

$-

显示shell使用的当前选项,与set命令功能同

$* 与 $@ 区别

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

 

3.2.3.2 预定义变量

基本介绍

        事先定义好的变量,直接在shell脚本中使用

基本语法

命令

功能描述

$$

当前进程号(PID)。对于Shell脚本,就是这些脚本所在的进程 ID。

$!

后台运行的最后一个进程的进程号(PID)

$?

最后一次执行的命令返回的状态。如果这个变量的值为0,证明上一个命令正确执行;如果这个变量的值为非0(具体哪个数,由命令自己来决定),则证明上一个命令执行出错。

[root@localhost sh]$ ls
count.sh hello.sh parameter2.sh parameter.sh   #ls命令正确执行
[root@localhost sh]$ echo $?   #预定义变量“$?”的值是0,证明上一个命令执行正确
[root@localhost sh]$ ls install.log
ls:无法访问install.log:没有那个文件或目录  #当前目录中没有install.log文件,所以ls命令报错了
[root@localhost sh]$ echo $?
2
#变量“$?”返回一个非О的值,证明上一个命令没有正确执行
#至于错误的返回值到底是多少,是在编写ls命令时定义好的,如果碰到文件不存在就返回数值2
[root@localhost sh]$ vi variable.sh
#!/bin/bash
echo "The current process is $$"
#输出当前进程的PID.
#这个PID就是variable.sh这个脚本执行时,生成的进程的PID
find /root -name hello.sh &
#使用find命令在root目录下查找hello.sh文件
#符号&的意思是把命令放入后台执行,工作管理我们在系统管理章节会详细介绍
echo "The last one Daemon process is $!"
#输出这个后台执行命令的进程的PID,也就是输出find命令的PID号

3.2.4 read读取控制台输入

基本语法

read [选项][变量名]

read [选项][变量名]

选项

-p: “提示信息”:在等待read输入时,输出提示信息

-t: 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间

-a : 后跟一个变量,该变量会被认为是个数组,然后给其赋值,默认是以空格为分割符。

-n: 数字:read命令只接受指定的字符数,就会执行

-s: 隐藏输入的数据,适用于机密信息的输入

-d: 后面跟一个标志符,其实只有其后的第一个字符有用,作为结束的标志。

-e: 在输入的时候可以使用命令补全功能。

[root@localhost sh]$ vi read.sh
#!/bin/bash

read -t 30 -p "Please input your name: " name
#提示“请输入姓名”并等待30 秒,把用户的输入保存入变量name 中
echo "Name is $name"
#看看变量“$name”中是否保存了你的输入

read -s -t 30 -p "Please enter your age: " age
#提示“请输入年龄”并等待30秒,把用户的输入保存入变量age中
#年龄是隐私,所以我们用“-s”选项隐藏输入
echo -e "\n"
#调整输出格式,如果不输出换行,一会的年龄输出不会换行
echo "Age is $age"

read -n 1 -t 30 -p "Please select your gender[M/F]:" gender
#提示“请选择性别”并等待30秒,把用户的输入保存入变量gender
#使用“-n1”选项只接收一个输入字符就会执行(都不用输入回车)
echo -e "\n"
echo "Sex is $gender"
#!/bin/sh
  
echo "please input your name and age:"
read -t 20 -p "name: " name     #限时20秒内输入name的值 -p 后面跟提示信息,即在输入前打印信息
read -t 20 -p "age: " age       #限时20秒内输入age的值
echo "your name is "$name", your age is $age"  # shell 脚本输出变量:$变量名

3.3 字符串

字符串可用引号,也可用引号,也可不用引号。

如果字符串中无空格特殊字符,不加引号也可以。如果字符串中无空格特殊字符,不加引号也可以。

错例str=Hello Tom 中间出现了空格, Tom被当做命令对待。

建议】字符串应该加引号

3.3.1 单双引号的区别

单引号字符串的限制

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

your_name="runoob"
str="Hello, I know you are \"$your_name\"! \n"
echo -e $str

Hello, I know you are "runoob"!

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

3.3.2 字符串操作

3.3.2.1 拼接字符串

your_name="runoob"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1

# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name}'#单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
echo $greeting_2  $greeting_3

#使用+号拼接
greeting_4="hello,"
greeting_4+=${your_name}
echo $greeting_4

输出结果:

hello, runoob ! hello, runoob !

hello, runoob ! hello, ${your_name}

hello, runoob

3.3.2.2 获取字符串长度

变量为字符串时,${#string} 等价于 ${#string[0]}:

string="abcd"
echo ${#string}   # 输出 4
echo ${#string[0]}   # 输出 4
3.3.2.3 提取字符串

$[string:index:len]

string="runoob is a great site"
echo ${string:1:4} # 输出 unoo
#注意:第一个字符的索引值为 0
3.3.2.4 查找字符串

注意: 脚本中 ` 是反引号,而不是单引号 ',不要看错了哦。

string="runoob is a great site"
echo `expr index "$string" io`  # 输出 4
echo `expr index "$string" a`  # 输出 11
3.3.2.5 替换字符

替换字符串str中第一个出现的子字符串src:$(str/src/dst/)

替换字符串str中所有出现的字串src:$(str//src/dst/)

str=/sir1/dir2/dir3/test
echo ${str/dir/path}   #/path1/path2/path3/test

echo ${str//dir/path}   #/path1/dir2/dir3/test
echo ${str//[!0-9]/}    #123
#str中所有非数字字符替换成空。注意:!的作用。
#把!去掉,表明把所有数字替换成空,即去掉数字,则输出:/dir/dir/dir/test
3.3.2.6 掐头去尾

通过#%对字符串操作

#是去掉边(键盘上#$的左边)

%是去掉边(键盘上%$的右边)

一符号是最小匹配:个符号是最大匹配(贪婪性

命令

说明

$(str#c)

删除字符串头部c,如果字符串前面字符不等于c,则删除无作用

$(str#*c)

删除字符串第一个出现的c,以及左边的字符,如果字符串前面没有字符c,则操作无作用

$(str##c)

删除字符串头部c,如果字符串前面字符不等于c,则删除无作用

$(str##*c)

删除字符串最后一个出现的c,以及左边的字符,如果字符串前面没有字符c,则操作无作用

$(str%c)

删除字符串尾部c,如果字符串尾部字符不等于c,则删除无作用

$(str%c*)

删除字符串最后出现的c,以及右边的字符,如果字符串没有字符c,则操作无作用

$(str%%c)

删除字符串尾部c,如果字符串尾部字符不等于c,则删除无作用

$(str%%c*)

删除字符串最先出现的c,以及右边的字符,如果字符串没有字符c,则操作无作用

3.3.2.7 获取最后n个字符

${var: -n} :和-n之间必须有空格

XmDdrSize=2G
${XmDdrSize: -1}     #G
${XmDdrSize: -2}     #2G

3.4 shell数组

bash支持一维数组(不支持多维数组),并且没有限定数组的大小。

类似于 C 语言,数组元素的下标由 0 开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于 0。

#用括号来表示数组,数组元素用"空格"符号分割开
数组名=(值1 值2 ... 值n)
定义数组
array_name=(value0 value1 value2 value3)
------------------------------------------
array_name=(
value0
value1
value2
value3
)
--------------------------------------------
#单独定义数组的各个分量,可以不使用连续的下标
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen
读取数组
${数组名[下标]}

如:
valuen=${array_name[n]}
--------------------------------------
#使用@或*符号获取数组中所有的元素
echo ${array_name[@]}
echo ${array_name[*]}
获取数组的长度
# 取得数组元素的个数
length=${#array_name[@]}
# 或者
length=${#array_name[*]}
# 取得数组单个元素的长度
lengthn=${#array_name[n]}
关联数组

可以使用任意字符串、或整数作为下标来访问数组元素。使用declare命令来声明

declare -A array_name

-A 选项用于声明一个关联数组。

关联数组的键是唯一的

#创建一个关联数组并创建不同的键和值
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"


# 通过键来访问关联数组的元素值
echo ${site["runoob"]}    #输出 www.runoob.com

# 在数组前加一个感叹号 ! 可以获取数组的所有键
echo "数组的键为: ${!site[*]}"       #输出 数组的键为: google runoob taobao
echo "数组的键为: ${!site[@]}"       #输出 数组的键为: google runoob taobao

3.5 注释

3.5.1 单行注释

在每一行前添加 #

3.5.2 多行注释
:<<EOF
注释内容...
注释内容...
注释内容...
EOF

-------------
#EOF 也可以使用其他符号
-------------
:<<'
注释内容...
注释内容...
注释内容...
'

:<<!
注释内容...
注释内容...
注释内容...
!

3.6 运算符

3.6.1 基本计算工具 expr

$((运算式)) $[运算式]

awk和expr是一款表达式工具,能完成表达式的求值操作。

expr m + n 注:expr运算符之间要有空格

expr m - n

expr *,/、%

#!/bin/sh
 
RESUALT1=$(((2+3)*4))
echo "RESUALT1 = $RESUALT1"
RESUALT2=$[(2+3)*4]
echo "RESUALT2 = $RESUALT2"
#使用expr
TEMP=`expr $1 + $2`
RESUALT3=`expr $TEMP \* 4`
echo "RESUALT3 = $RESUALT3"

注意:

  • 乘号(*)前边必须加反斜杠(\)才能实现乘法运算;
  • 在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "\" 

3.6.2 算术运算符

运算符

说明

举例 (a = 10 b = 20)

+

加法

`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。

#!/bin/bash
read -p "please input operand and number: " operand number
echo "$operand + $number = $(($operand+$number))"
echo "$operand - $number = $(($operand - $number))"
echo "$operand * $number = $(($operand * $number))"
divided=$(($operand/$number))		#赋值等号间不能有空格!
echo "$operand / $number = $divided"

3.6.3 关系运算符

运算符

说明

举例 (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 -le $b ] 返回 true。

3.6.4 布尔运算符

运算符

说明

举例 (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。

3.6.5 逻辑运算符

运算符

说明

举例 (a = 10 b = 20)

&&

逻辑的 AND

[[ $a -lt 100 && $b -gt 100 ]] 返回 false

||

逻辑的 OR

[[ $a -lt 100 || $b -gt 100 ]] 返回 true

3.6.6 字符串运算符

运算符

说明

举例 (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。

3.6.7 文件测试运算符

操作符

说明

举例

-b file

检测文件是否是块设备文件,如果是,则返回 true。

[ -b $file ] 返回 false。

-c file

检测文件是否是字符设备文件,如果是,则返回 true。

[ -c $file ] 返回 false。

-d file

检测文件是否是目录,如果是,则返回 true。

[ -d $file ] 返回 false。

-e file

检测文件(包括目录)是否存在,如果是,则返回 true。

[ -e $file ] 返回 true。

-f file

检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。

[ -f $file ] 返回 true。

-g file

检测文件是否设置了 SGID 位,如果是,则返回 true。

[ -g $file ] 返回 false。

-k file

检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。

[ -k $file ] 返回 false。

-p file

检测文件是否是有名管道,如果是,则返回 true。

[ -p $file ] 返回 false。

-u file

检测文件是否设置了 SUID 位,如果是,则返回 true。

[ -u $file ] 返回 false。

-r file

检测文件是否可读,如果是,则返回 true。

[ -r $file ] 返回 true。

-w file

检测文件是否可写,如果是,则返回 true。

[ -w $file ] 返回 true。

-x file

检测文件是否可执行,如果是,则返回 true。

[ -x $file ] 返回 true。

-s file

检测文件是否为空(文件大小是否大于0),不为空返回 true。

[ -s $file ] 返回 true。

-S file

判断某文件是否 socket。

[ -S $file ] 返回 true。

-L file

检测文件是否存在并且是一个符号链接

[ -L $file ] 返回 true。

3.7 条件判断

3.7.1 判断语句

基本语法

[ condition ] 注:condition前后都要有空格

#非空返回true,可使用$?验证(0为true,>1为false)

3.7.2 常用判断条件

文件表达式

-e filename

如果 filename存在,则为真

-d filename

如果 filename为目录,则为真

-f filename

如果 filename为存在并为常规文件,则为真

-L filename

如果 filename为符号链接,则为真

-r filename

如果 filename可读,则为真

-w filename

如果 filename可写,则为真

-x filename

如果 filename可执行,则为真

-s filename

如果文件长度不为0,则为真

-h filename

如果文件是软链接,则为真

filename1 -nt filename2

如果 filename1比 filename2新,则为真。

filename1 -ot filename2

如果 filename1比 filename2旧,则为真。

整数变量表达式

-eq

= if [ 22 -eq 18 ]

-ne

!= if [ 22 -ne 18 ]

-gt

>

-ge

-lt

-le

字符串变量表达式

If [ $a = $b ]

如果string1等于string2,则为真,字符串允许使用赋值号做等号

if [ $string1 != $string2 ]

如果string1不等于string2,则为真

if [ -n $string ]

如果string 非空(非0),返回0(true)

if [ -z $string ]

如果string 为空,则为真

if [ $sting ]

如果string 非空,返回0 (和-n类似)

逻辑非!

if [ ! 表达式 ]

条件表达式的相反

if [ ! -d $num ]

如果不存在目录$num

逻辑与 –a

if [ 表达式1 –a 表达式2 ]

条件表达式的并列

逻辑或 -o

if [ 表达式1 –o 表达式2 ]

条件表达式的或

3.7.3 中括号判断符

字符串判断:

#!/bin/bash
read -p "please input first string: " firstStr
read -p "please input second string: " secondStr
[ "$firstStr" == "$secondStr" ] && echo "The two strings are the same" || echo "The two strings are not the same"
# 中括号两端内测要加空格,内容建议加 "",否则有空格时会出现参数过多
[ "$firstStr" != "$secondStr" ] && echo "The two strings are not the same" || echo "The two strings are the same"
[ "$firstStr" = "$secondStr" ] && echo "The two strings are the same" || echo "The two strings are not the same"
echo firstStr:  $firstStr
echo secondStr: $secondStr

3.8 流程控制

3.8.1 if判断

基本语法


if [ 条件判断式 ];then
	# 判断成立后要执行的语句
fi				# 结束语句

--------------------------------------------------------------------

if [ 条件判断式 ]; then
	# 条件判断后成立要执行的语句
else
	# 条件判断后不成立要执行的语句
fi

--------------------------------------------------------------------

if [ 条件判断式 ]; then
	# 条件判断后成立要执行的语句
elif [ 条件判断式 ]; then		# 此语句可多次添加
	# 条件判断后成立要执行的语句
else
	# 条件判断后不成立要执行的语句
fi

注意事项:

  1. [ 条件判断式 ],中括号和条件判断式之间必须有空格;
  2. 推荐使用第二种方式
#!/bin/bash

read -p "please input(Y/N):" value

if [ "$value" == "Y"  ] || [  "$value" == "y" ]; then
        echo "your input is Y"
        exit 0
fi

if [ "$value" == "N"  ] || [  "$value" == "n" ]; then
        echo "your input is N"
        exit 0
fi

注意事项

if else 的 [...] 判断语句中大于使用 -gt,小于使用 -lt

if [ "$a" -gt "$b" ]; then
    ...
fi

如果使用 ((...)) 作为判断语句,大于和小于可以直接使用 ><

if (( a > b )); then
    ...
fi

3.8.2 case语句

C语言中的 switch ... case 语句类似,是一种多分支选择结构

case 语句匹配一个值或一个模式,如果匹配成功,执行相匹配的命令

case $变量名 in		# 与 C语言 switch case 相似
"第一个变量内容")
	# 程序段
	;;		# 表示第一个程序块结束
"第二个变量内容" | "第三个变量内容")  #不同变量内容相同处理方式合并,使用“|”,其前后加空格都可
	# 程序段
	;;		# 表示第二个程序块结束
"第n个变量内容")
	# 程序段
	;;		# 表示第 n个程序块结束
*)			# 类似 C语言 switch case的 default
	# 程序段
	;;
esac
#!/bin/bash

case $1 in
  "a")
     echo "param is :a"
     ;;
   "b")
     echo "param is :b"
     ;;
   *)#这里通配符不能加上引号 加上就代表字符*了
     echo "can't identify"
     ;;
esac

3.8.3 循环语句

while [ 条件判断式 ]			# 条件状态为判断式,条件成立时循环,直到条件不成立
  do					# 循环开始
  	# 循环代码段
  done

--------------------------------------------------------------------

until [ 条件判断式 ]			# 条件状态为判断式,条件不成立时循环,直到条件成立
  do					# 循环开始
  	# 循环代码段
  done

--------------------------------------------------------------------

for var in con1 con2 con3 ......
  do
  	# 循环代码段
  done
# 变量 var 循环变化,第一次循环等于 con1,第二次循环等于 con2,以此类推

--------------------------------------------------------------------

for((初始值;循环控制条件;执行步长))
  do
  	# 循环代码段
  done
# 用法类似于 C语言 for循环
#!/bin/bash

while [ "$value" != "close" ]
  do
      read -p "please input str:" value
  done

echo "stop while!!"

--------------------------------------------

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

a=0

until [ ! $a -lt 10 ]
  do
     echo $a
     a=`expr $a + 1`
  done
#!/bin/bash
for name in zxg1 zxg2 zxg3
  do
      echo "name = $name"
  done
#!/bin/bash
for((count=0;count<=10;count++))
  do
      echo "$count"
  done

3.8.4 特殊流程控制语句

break语句

跳出所有循环(终止执行后面的所有循环)

continue语句

不会跳出所有循环,仅仅跳出当前循环,而下次循环会继续

用于从whileuntilforselect等循环中退出。

语法

        break/continue n

        n表示跳出循环的层数,如果省略n,则表示跳出当前循环

区别

        break跳出循环,从循环外的后面脚本开始执行。

        continue跳出循环,回到循环的开始处执行。

 类似C语言breakcontinue语句,但C语言中不带参数n

#【例子】从终端读取输入的正数,求和,输入0时,终止循环

sum=0
 
while read n
do
       [ n -eq 0 ] && { break; }
 
if [ n -lt 0 ]; then
       continue;
else
sum=$((sum+n))
 fi
done
 
echo "sum=$sum"

exit语句

在Shell脚本中,只要碰到了exit语句,后续的程序就不再执行,而直接退出脚本

exit [ 返回值 ]

*** 如果exit命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。可通过查询$?这个变量,来查看返回值

*** 如果exit之后没有定义返回值,脚本执行之后的返回值是执行exit 语句之前,最后执行的一条命令的返回值。

3.9 管道

作用:将两个或多个命令连到一起,把一个命令的输出作为下一个命令的输入

管道符:|

语法:command1 | command2 [ | command N...]

#列举所有文件属性,找到log.txt这一行,保存到文件output.txt中。
ls -al | grep log.txt > output.txt
#使用cat命令打印输出文件内容
cat output.txt

前提条件:管道符前面的命令必须有正确的输出,后面的命令可以从标准输入读取,并能处理前面命令的输出结果。

说明:后面命令只能处理前面命令正确输出结果,而不能处理错误信息

建议:在管道符前后尽量加空格,增强可读性。

3.10 重定向

重定向操作符将命令文件(包括标准输入输出描述符)连接起来

Ø 命令接收文件输入
Ø 把命令的输出输给 文件

3.10.1 重定向vs管道

管道也有重定向的作用,也改变了数据输入输出的方向

3.11 函数

3.11.1 函数介绍

shell编程和其它编程语言一样,有系统函数,也可以自定义函数。

函数(function)若干Shell命令组成的语句块,实现代码重用模块化编程

        不是一个单独的进程,不能独立运行,需要在脚本中调用它,能起作用

3.11.2 系统函数

basename

功能:返回完整路径最后/ 的部分常用于获取文件名 basename [pathname] [suffix]

basename [string] [suffix]  
#basename命令会删掉所有的前缀包括最后一个(‘/’) 字符,然后将字符串显示出来
#选项: suffix为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉

//请返回 /home/zhangxiaogang/zxg/shellcode/read.sh 的“read.sh”部分

dirname

功能:返回完整路径最后/ 的前面的部分,常用于返回路径部分

dirname 文件绝对路径 
#从给定的包含绝对路径的文件名中去除文件名(非目录的部分), 然后返回剩下的路径(目录的部分)

//请返回 /home/zhangxiaogang/zxg/shellcode/read.sh 的“ /home/zhangxiaogang/zxg/shellcode”部分

3.11.3 自定义函数

function fname(){		# function 可写可不写  ()可以省略
	# 函数代码段
}

fname		# 函数调用

fname param1 param2		# 函数传参

说明:

  • 1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
  • 2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255
#!/bin/bash
fun1(){
    echo "$0"
    echo "param1:$1"
    echo "param2:$2"
    echo "$#"
    echo "$@"
}

fun1 lcx1 lcx2 #函数调用和传参

3.12 echo命令

Shell命令:echo 命令详解

3.12.1 显示普通字符串

echo "It is a test"
echo It is a test

3.12.2 显示转义字符

echo "\"It is a test\""    #输出 "It is a test"
echo \"It is a test\"      #输出 "It is a test"

3.12.3 显示变量

#!/bin/sh
read name 
echo "$name It is a test"

3.12.4 显示换行

echo -e "OK! \n"        # -e 开启转义
echo "It is a test"

# 输出结果:
# OK!

# It is a test

3.12.5 显示不换行

#!/bin/sh
echo -e "OK! \c"        # -e 开启转义 \c 不换行
echo "It is a test"

# 输出结果:
# OK! It is a test

3.12.6 显示结果定向至文件

echo "It is a test" > myfile.txt    #表示清空文件的内容

echo "It is a test" >> myfile.txt   #表示对文件的追加,不会清空文件,echo的内容追加到文件的后面

3.12.7 原样输出字符串,不进行转义或取变量(用单引号)

echo '$name\"'        #输出  $name\"

3.12.8 显示命令执行结果

echo `date`    # 结果将显示当前日期 Thu Jul 30 10:08:46 CST 2023

3.13 printf命令

printf format-string [arguments...]

参数说明:

  • format-string: 为格式控制字符串
  • arguments: 为参数列表。

%s 输出一个字符串,

%d 整型输出,

%c 输出一个字符,

%f 输出实数,以小数形式输出。

%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。

%-4.2f 指格式化为小数,其中 .2 指保留2位小数。

3.13.1 printf的转义序列

序列

说明

\a

警告字符,通常为ASCII的BEL字符

\b

后退

\c

抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略

\f

换页(formfeed)

\n

换行

\r

回车(Carriage return)

\t

水平制表符

\v

垂直制表符

\\

一个字面上的反斜杠字符

\ddd

表示1到3位数八进制值的字符。仅在格式字符串中有效

\0ddd

表示1到3位的八进制值字符

3.14 test命令

用于查看文件是否存在、权限等信息,可以进行数值、字符和文件三方面的测试

cmd1 && cmd2
#当 cmd1 执行完毕且正确,那么 cmd2 执行,当 cmd1 执行完毕且错误,那么 cmd2 不执行

cmd1 || cmd2
#当 cmd1 执行完毕且正确,那么 cmd2 不执行,当 cmd1 执行完毕且错误,那么 cmd2 执行

3.14.1 数值测试

参数

说明

-eq

等于则为真

-ne

不等于则为真

-gt

大于则为真

-ge

大于等于则为真

-lt

小于则为真

-le

小于等于则为真

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

3.14.2 字符串测试

参数

说明

=

等于则为真

!=

不相等则为真

-z 字符串

字符串的长度为零则为真

-n 字符串

字符串的长度不为零则为真

#!/bin/sh
read -p "please input first string: " firstStr
read -p "please input second string: " secondStr
test $firstStr = $secondStr && echo "The two strings are the same" || echo "The two strings are not the same"
# test str1 = str2 :两个字符串相等则为真

3.14.3 文件测试

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

参数

说明

-e 文件名

如果文件存在则为真

-r 文件名

如果文件存在且可读则为真

-w 文件名

如果文件存在且可写则为真

-x 文件名

如果文件存在且可执行则为真

-s 文件名

如果文件存在且至少有一个字符则为真

-d 文件名

如果文件存在且为目录则为真

-f 文件名

如果文件存在且为普通文件则为真

-c 文件名

如果文件存在且为字符型特殊文件则为真

-b 文件名

如果文件存在且为块特殊文件则为真

#!/bin/sh
read -p "please input file name: " filename
test -e $filename && echo "$filename exist" || echo "$filename non-existence"
# test -e :如果文件存在则为真

3.15 文件包含

包含外部脚本。这样可以很方便的封装一些公用的代码作为一个独立的文件

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

或

source filename

实例:

创建两个 shell 脚本文件。

#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

url="http://www.runoob.com"
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

#使用 . 号来引用test1.sh 文件
. ./test1.sh

# 或者使用以下包含文件代码
# source ./test1.sh

echo "菜鸟教程官网地址:$url"

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

$ chmod +x test2.sh

$ ./test2.sh

菜鸟教程官网地址:http://www.runoob.com

注:被包含的文件 test1.sh 不需要可执行权限。

3.16其他指令

3.16.1 tr 内容替换

# echo 'HELLO WORLD!!!' | tr "A-Z" "a-z"
hello world!!!

这里的"A-Z"、"a-z"都表示集合,shell脚本中定义集合类型很简单,即指定集合序列即可,但是对于上边的情形,不得非输入所有集合类型,可以通过“开始字符-结束字符”方式进行集合定义。使用tr命令结合集合使用,可以解决很多复杂问题。
————————————————————————————————————————————————————————————————————————————————————————
使用tr进行数据加密,解密:

# echo 456 | tr "0-9" "9876543210"
543

# echo 543 | tr "9876543210" "0-9"
456
————————————————————————————————————————————————————————————————————————————————————————
tr进行字符替换:

# cat dept

10    ACCOUNTING    NEW YORK
20    RESEARCH    DALLAS
30    SALES    CHICAGO
40    OPERATIONS    BOSTON

# cat dept | tr "\t" " "

10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
————————————————————————————————————————————————————————————————————————————————————————
指定-d参数删除指定字符串:

# echo 'hello 123 world 456 !!!' | tr -d '{0-9}'
hello  world  !!!
————————————————————————————————————————————————————————————————————————————————————————
指定-c参数进行补集处理,通常与-d连用,删除不满足条件的字符:

# echo 'hello 123 world 456 !!!' | tr -d -c '{0-9 \n}'
123  456
————————————————————————————————————————————————————————————————————————————————————————
tr命令中-s参数进行字符压缩,将连续的重复字符压缩成当个字符,最常见的场景就是压缩空白格:

# echo 'hello           123              world             456 !!!' | tr -s ' '
hello 123 world 456 !!!
————————————————————————————————————————————————————————————————————————————————————————
技巧:使用tr将文件中的字符列表相加:

# seq 5 | echo $[ $( tr '\n' '+' ) 0 ]
15

解释:将\n替换成+后,脚本输出变成$[ 1+2+3+4+5+0 ],可以直接进行加法计算,省去循环读取数字的麻烦。
————————————————————————————————————————————————————————————————————————————————————————
tr也可以像集合一样使用各种不同的字符类。

sed和tr替换换行符:sed ':label;N;s/,\n/,/;b label ; tr '\n' ','

ps:初步学习整理,望诸位大神批评、指点!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

struggle3436

你的鼓励将是我创作最大的动力❀

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值