Shell
2025-08-22 16:03:10,

Shell

什么是Shell

Shell是一个命令行解释器,它接收应用程序/用户命令,然后调用操作系统内核

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁

Shell还是一个功能相当强大的编程语言,易编写、易调试、灵活性强。

Shell 编程跟 JavaPHP 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了

入门

Linux 的 Shell 种类众多,常见的有:C++at /etc/shells

Bash由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数 Linux 系统默认的 Shell。

echo $SHELL

输出默认shell

脚本以#!/bin/bash 开头(指定解析器)

案例

vim helloworld.sh 在 helloworld.sh 中输入如下内容

 #!/bin/bash
 echo "helloworld" 

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

脚本的常用执行方式

第一种:采用 bash 或 sh+脚本的相对路径或绝对路径(不用赋予脚本+x 权限)

(1)sh+脚本的相对路径。sh ./helloworld.sh

helloworld

(2)sh+脚本的绝对路径。 sh /home/atguigu/helloworld.sh

helloworld

(3)bash+脚本的相对路径。 bash ./helloworld.sh

helloworld

(4)bash+脚本的绝对路径。 bash /home/atguigu/helloworld.sh

helloworld

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

第二种:采用输入脚本的绝对路径或相对路径执行脚本(必须具有可执行权限+x)

(1)首先要赋予 helloworld.sh 脚本的+x 权限 chmod +x helloworld.sh

(2)执行脚本

① 相对路径。 ./helloworld.sh

helloworld

② 绝对路径。 /home/atguigu/helloworld.sh

helloworld

注意:第一种执行方法,本质是 bash 解析器帮你执行脚本,所以脚本本身不需要执行 权限。

第二种执行方法,本质是脚本需要自己执行,所以需要执行权限。

变量

语法:$变量名

$和变量名之间不能有空格。

echo $HOME 查看系统变量的值

显示当前Shell中所有的变量 env/set

自定义变量

语法

(1)定义变量:变量名=变量值,注意,=号前后不能有空格。

(2)撤销变量:unset 变量名。

(3)声明静态变量:readonly 变量,注意:不能 unset。

定义规则

(1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建 议大写

(2)等号两侧不能有空格。

(3)在 bash 中,变量默认类型都是字符串类型,无法直接进行数值运算。

(4)变量的值如果有空格,需要使用双引号或单引号括起来。

案例实操

1 定义变量A

A=5

echo $A

2 给A重新赋值

A=8

echo $A

3 撤销变量A

unset A

4 声明静态的变量B

readonly B=2

echo $B

设定好就修改不了

5 在bash中变量默认的类型都是字符串类型,无法直接进行数值运算

C=1+2

echo $C

6 变量的值如果有空格,需要用双引号或单引号括起来

D="I love banzhang"

echo $D

7 可把变量提升为全局环境变量

export B

在helloworld.sh中加入 echo $B

打印输出

./helloworld.sh

特殊变量

$n

(功能描述:n 为数字,$0 代表该脚本名称,$1-$9 代表第一到第九个参数,十以上 的参数需要用大括号包含,如${10}。)

案例实操

vim parameter.sh

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 

chmod 777 parameter.sh

 ./parameter.sh cls xz 
 ==========$n========== 
./parameter
.sh
 cls

$#

(功能描述:获取所有输入参数个数,常用于循环,判断参数的个数是否正确)

在上述parameter.sh后面加入 $#

$*$@

$* (功能描述:这个变量代表命令行中所有的参数,$*把所有的参数看成一个整体。)

$@ (功能描述:这个变量也代表命令行中所有的参数,不过$@把每个参数区分对待。)

在上述parameter.sh后面加入 $*$@

echo $* $@

$*和$@的区别需要结合循环说明

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


$?

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

执行上述脚本parameter.sh

输入echo $? 判断脚本是否正确的执行

atguigu@ubuntu:~$ ./helloworld.sh
hello world
atguigu@ubuntu:~$ echo $?
0

运算符

Shell 和其他编程语言一样,支持多种运算符,包括:

  1. 算数运算符
  2. 关系运算符
  3. 布尔运算符
  4. 字符串运算符
  5. 文件测试运算符

基本语法

test condition

[ condition ](注意 condition 前后要有空格)

注意:条件非空即为 true,[ atguigu ]返回 true,[ ] 返回 false。

有两个 1是用test来进行测试 2 是用[ ]来进行测试 没有返回结果值 需要输入$? 来看结果对不对

1 算术运算符

下表列出了常用的算术运算符,假定变量 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。

注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。

乘号(*)前边必须加反斜杠()才能实现乘法运算

"$((运算式))" 或 "$[运算式]"
1)计算(2+3)* 4 的值
(1)$[]
atguigu@ubuntu:~$ S=$[(2+3)*4]
atguigu@ubuntu:~$ echo $S
(2)$(())
atguigu@ubuntu:~$ unset S
atguigu@ubuntu:~$ S=$(((2+3)*4))
atguigu@ubuntu:~$ echo $S
20

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 -le $b ] 返回 true。
(1)判断23 是否大于等于 22 
1  test         
 test 23 -ge 22  
 echo $? 0 
2 [ condition ]      
   [ 23 -ge 22 ] 
   echo $?
   0 

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。

4 逻辑运算符

以下介绍 Shell 的逻辑运算符,假定变量 a 为 10,变量 b 为 20:

运算符 说明 举例
&& 逻辑的 AND [[ $a -lt 100 && $b -gt 100 ]] 返回 false
|| 逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true
多条件判断(&& 表示前一条命令执行成功时,才执行后一条命令,|| 表示上一条命令 执行失败后,才执行下一条命令) 
1 testcondition 
test atguigu && echo OK || echo notOK    OK 
test && echo OK || echo notOK       notOK
 2 [ condition ] 
[ atguigu ] && echo OK || echo notOK     OK 
[ ] && echo OK || echo notOK                    notOK

4 字符串运算符

下表列出了常用的字符串运算符,假定变量 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。
str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true。

5 文件测试运算符

按照文件类型进行判断

  • -e 文件存在(existence)
  • -f 文件存在并且是一个常规的文件(file)
  • -d 文件存在并且是一个目录(directory)
3)/home/atguigu/cls.txt 目录中的文件是否存在
1  test condition
  test -e /home/atguigu/cls.txt    
 echo 
 $?
 1 
2
[ condition ] 
[ -e /home/atguigu/cls.txt ] 
echo $? 
1 

6 文件的权限

按照文件权限进行判断 -r 有读的权限(read) -w 有写的权限(write) -x 有执行的权限(execute)

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

流程控制

if

if 判断

基本语法

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

注意事项: ① [ 条件判断式 ],中括号和条件判断式之间必须有空格 ② if 后要有空格

案例实操 输入一个数字,如果是 1,则输出 banzhang zhen shuai,如果是 2,则输出 cls zhen mei, 如果是其它,什么也不输出。

vim if.sh 写入以下内容

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

case

case $变量名 in

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

注意事项:

(1)case 行尾必须为单词“in”,每一个模式匹配必须以右括号“)”结束。

(2)双分号“;;”表示命令序列结束,相当于 C 中的 break。

(3)最后的“)”表示默认模式,相当于 C 中的 default。

案例

输入一个数字,如果是 1,则输出 banzhang,如果是 2,则输出 cls,如果是其它,输出 renyao。 vim case.sh

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

chmod 777 case.sh

./case.sh 1

./case.sh 2

./case.sh 3

**fore **

1 for ((初始值;循环控制条件;变量变化))

do 程序

done

vim for1.sh

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

chmod 777 for1.sh

./for1.sh

2 for 变量 in 值 1 值 2 值 3…

do

程序

done

vim for2.sh

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

3 比较$*和$@区别 *

1 $和$@都表示传递给函数或脚本的所有参数,不被双引号“”包含时,都以$1 $2 …$n 的形式输出所有参数

vim for3.sh

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

2 当它们被双引号“”包含时,$*会将所有的参数作为一个整体,以“$1 $2 …$n”的形 式输出所有参数;$@会将各个参数分开,以“$1” “$2”…“$n”的形式输出所有参数

vim for4.sh

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

while

基本语法

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
0

案例实操

vim while.sh

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
1

退出循环

跳出循环

在循环过程中,有时候需要在未达到循环结束条件时强制跳出循环,Shell使用两个命令来实现该功能:break和continue。

break命令

break命令允许跳出所有循环(终止执行后面的所有循环)。

下面的例子中,脚本进入死循环直至用户输入数字大于5。要跳出这个循环,返回到shell提示符下,需要使用break命令。

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
2

执行以上代码,输出结果为:

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
3

continue

continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

对上面的例子进行修改:

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
4

运行代码发现,当输入大于5的数字时,该例中的循环不会结束,语句 echo "Game is over!" 永远不会被执行。

read

读取控制台输入输出

read

-p 指定读取值时的提示符

-t 指定读取值时等待的时间 如果-t不加表示一直等待

变量 指定读取值的变量名

7秒内读取控制台的输入

vim read.sh

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
5

函数

基本函数

basename

basename [string / pathname] [suffix] (功能描述:basename 命令会删掉所有的前 缀包括最后一个(‘/’)字符,然后将字符串显示出来。

basename 可以理解为取路径里的文件名称。

选项: suffix 为后缀,如果 suffix 被指定了,basename 会将 pathname 或 string 中的 suffix 去掉

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
6

dirname

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

dirname 可以理解为取文件路径的绝对路径名称。

获取banzhang.txt在此文件夹下的绝对路径

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
7

自定义函数

function

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
8

经验技巧 (1)必须在调用函数地方之前,先声明函数,shell 脚本是逐行运行。不会像其它语言 一样先编译。

(2)函数返回值,只能通过$?系统变量获得,可以显示加:return 返回,如果不加, 将以最后一条命令运行结果,作为返回值。return 后跟数值 n(0-255)。

计算两个输入参数的和 vim run.sh

#!/bin/bash 
echo '==========$n==========' 
echo $0 
echo $1 
echo $2 
9

函数参数

$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数

在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...

带参数的函数示例:

 ./parameter.sh cls xz 
 ==========$n========== 
./parameter
.sh
 cls
0

输出结果:

 ./parameter.sh cls xz 
 ==========$n========== 
./parameter
.sh
 cls
1

Shell工具

cut

的 ^代表开始 $代表结束

cut 的工作就是“剪”,具体的说就是在文件中负责剪切数据用的。

cut 命令从文件的 每一行剪切字节、字符和字段并将这些字节、字符和字段输出。

cut [选项参数]

-f 提取第几列

-d 分隔符 按照指定分隔符分割列

-c 按字符进行切割后加n表示第几列

 ./parameter.sh cls xz 
 ==========$n========== 
./parameter
.sh
 cls
2

awk

一个强大的文本分析工具,把文件逐行的读入,以空格为默认分隔符将每行切片,切开 的部分再进行分析处理。

awk [选项参数] ‘/pattern1/{action1} /pattern2/{action2}...’ filename pattern:

awk -F : '//{}' 文件名 标准格式

print输出

-F 指定输入文件的分隔符

-v 赋值一个用户定义变量

表示 awk 在数据中查找的内容,就是匹配模式。

action:在找到匹配内容时所执行的一系列命令。

BEGIN AND 添加添加一些内容

例题1

 ./parameter.sh cls xz 
 ==========$n========== 
./parameter
.sh
 cls
3

内置变量 变量 说明

FILENAME 文件名

NR 已读的记录数(行号)

NF 浏览记录的域的个数(切割后,列的个数)

例题2

 ./parameter.sh cls xz 
 ==========$n========== 
./parameter
.sh
 cls
4

正则表达式

正则表达式使用单个字符串来描述、匹配一系列符合某个语法规则的字符串。在很多文 本编辑器里,正则表达式通常被用来检索、替换那些符合某个模式的文本。在 Linux 中, grep,sed,awk 等命令都支持通过正则表达式进行模式匹配。

  • ^ 匹配一行的开头
  • $ 匹配一行的结束
  • ^$ 匹配空行
  • .匹配任意一个字符
  • *不单独使用,他和上一个字符连用,表示匹配上一个字符 0 次或多次
  • .*匹配任意字符
  • [ ]表示匹配某个范围内的字符[a-z]------匹配一个 a-z 之间的字符 [a-z]* ------匹配任意长度的字母字符串 [a-c, e-f]-匹配 a-c 或者 e-f 之间的任意字符,[6,8]------匹配 6 或者 8 [0-9]------匹配一个 0-9 的数字
  • 特殊字符 \ 表示转义,并不会单独使用。由于所有特殊字符都有其特定匹配模式,当我们想匹配 某一特殊字符本身时(例如,我想找出所有包含 '$' 的行)

10.4 经典正则表达式

#邮箱正则

[1]+@[a-zA-Z0-9_-]+(.[a-zA-Z0-9_-]+)+$ #手机号正则

/^1((34[0-8])|(8\d{2})(([35][0-35-9]|4[579]|66|7[35678]|9[1389])\d{1}))\d{7}$

  1. a-zA-Z0-9_- ↩︎