☰
【Shell脚本学习】
2026/10/27 1:17:56 网站建设 项目流程

目录

  • 1、运行shell脚本三种方式
  • 2、变量赋值
  • 3、字符串
  • 4、数组
  • 5、变量的值
  • 6、多行注释
  • 7、算术运算符
  • 8、关系运算符
  • 9、布尔运算符
  • 10、逻辑运算符
  • 11、字符串运算符
  • 12、文件测试运算符
  • 13、echo
  • 14、输入/输出重定向
  • 15、printf
  • 16、test
  • 17、流程控制
  • 18、let
  • 19、函数
  • 20、操作键盘输入
  • 21、select与case
  • 22、多命令逻辑执行顺序
  • 23、包含外部脚本
  • 24、获取进程ID
  • 25、杀进程
  • 26、xargs
  • 27、chattr
  • 28、自动输入sudo的密码

shell脚本格式: 第一行#!后面跟的是解释器的路径,shell本身是一种解释型语言

1、运行shell脚本三种方式

  • ./脚本文件
  • 调用解释器使得脚本执行(bash、csh、ash、bsh、ksh等),如:bash 脚本文件
  • source 脚本文件

分别用三种方式运行一个有cd命令的脚本:第一和第二种不会切换目录,第三种会切换。
因为第一第二种执行脚本时系统会创建一个子进程或者说子shell来执行脚本,原进程或父shell在整个过程中会等待子进程执行完毕,然后子进程退出,父进程也退出。cd命令确实被执行了,但是仅仅是在子进程中改变了工作目录,所以脚本执行完后使用pwd显示工作目录并没有改变。
而第三种执行的shell脚本并不创建子进程,就是在原来的进程中执行,所以最后的目录改变了。(一个脚本调用另一个脚本时,三种方式都不cd成功,因为cd是在被调用的脚本)

source FileName
作用:在当前 bash 环境下读取并执行 FileName 中的命令。该 filename 文件可以无 “执行权限”。
sh FileName 或 bash FileName
作用:打开一个子 shell 来读取并执行 FileName 中命令。该 filename 文件可以无 “执行权限”。
./FileName
作用: 打开一个子 shell 来读取并执行 FileName 中命令,该 filename 文件需要 “执行权限”。
注:运行一个 shell 脚本时会启动另一个命令解释器。

2、变量赋值

等号=前后不可以有空格
还可以语句赋值:for file in `ls /etc` 或 for file in $(ls /etc)
使用一个定义过的变量,在变量名前面加美元符号(使用时才加$,重新赋值时不用加),变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,推荐给所有变量加上花括号

欲想给变量赋一个命令的执行结果,例:var=`pidof processname`

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。(给只读变量赋值会报错,但会继续往下执行)

命令行可以这样使用:ll `pwd`/ipconfig

3、字符串

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

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

输出:

hello, runoob ! hello, runoob ! hello, runoob ! hello, ${your_name} !

获取字符串长度:

string="abcd" echo ${#string} #输出 4

提取子字符串:

string="runoob is a great site" echo ${string:1:4} # 从字符串第 2 个字符开始截取 4 个字符,输出 unoo

注意:第一个字符的索引值为 0。
更详细的字符串提取、截取:菜鸟教程(下面笔记)

查找子字符串,查找字符 i 或 o 的位置(哪个字母先出现就计算哪个):

string="runoob is a great site" echo `expr index "$string" io` # 输出 4

git组合命令:

git log --since=2021-10-01 --until=2021-10-31 --author=name --pretty=tformat: --numstat | awk '{ add += $1; subs += $2; loc += $1 - $2; total += $1 + $2 } END { printf " 新增代码行: %s\n 移除代码行: %s\n 总增加代码行: %s\n 总修改代码行: %s\n", add, subs, loc, total }'

4、数组

用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为: 数组名=(值1 值2 … 值n)
读取数组元素值的一般格式是:${数组名[下标]}
使用 @ 符号可以获取数组中的所有元素:echo ${array_name[@]}
获取数组元素的个数:length=${#array_name[@]} 或者 length=${#array_name[*]}
取得数组单个元素的长度:lengthn=${#array_name[n]}

5、变量的值

引用变量的值,例:$变量名
$0表示程序名,$1表示第1个参数,$2表示第2个参数, $n…
$* 这个程式的所有参数
$@ 跟$*类似,但是可以当作数组用
$# 这个程式的参数个数
$$ 这个程式的PID(脚本运行的当前进程ID号)
$! 执行上一个背景指令的PID(后台运行的最后一个进程的进程ID号)
$? 执行上一个指令的返回值 (显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误)
$- 显示shell使用的当前选项,与set命令功能相同

$0获取的文件名包括./以及路径等前缀信息,如果想仅得到文件名,而不包含./,可以使用basename命令:

name=`basename $0` echo The command entered is: $name

想获取所有的参数,当然可以利用$#和循环逐个遍历。也可以利用如下两个特殊变量:$*将所有的命令行参数看作一个整体存储,而$@将命令行中以空格间隔的参数单独存储,可测试打印:

forparamin"$*"forparamin"$@"echoThe last parameter is:${$#}# 按道理输出最后一个参数,实则不然。因为在花括号内不能使用$符号,而是以!来代替$工作,需要这样:echoThe last parameter is:${!#}

6、多行注释

:<<EOF
注释内容…
注释内容…
EOF
(EOF 也可以使用其他符号,如’、!)

7、算术运算符

+ 加法 `expr $a + $b` - 减法 `expr $a - $b` * 乘法 `expr $a \* $b` / 除法 `expr $b / $a` % 取余 `expr $b % $a` = 赋值 a=$b 将把变量 b 的值赋给 a == 相等。用于比较两个数字,相同则返回 true。 [ $a == $b ] != 不相等。用于比较两个数字,不相同则返回 true。 [ $a != $b ] 注意:条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。

8、关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值是数字。

-eq 检测两个数是否相等,相等返回 true。
-ne 检测两个数是否不相等,不相等返回 true。
-gt 检测左边的数是否大于右边的,如果是,则返回 true。
-lt 检测左边的数是否小于右边的,如果是,则返回 true。
-ge 检测左边的数是否大于等于右边的,如果是,则返回 true。
-le 检测左边的数是否小于等于右边的,如果是,则返回 true。

9、布尔运算符

! 非运算 -o 或运算 -a 与运算

10、逻辑运算符

&& 逻辑的 AND || 逻辑的 OR

11、字符串运算符

=检测两个字符串是否相等,相等返回 true。[$a=$b]!=检测两个字符串是否不相等,不相等返回 true。[$a!=$b]-z检测字符串长度是否为0,为0返回 true。[-z$a]-n检测字符串长度是否不为0,不为0返回 true。[-n"$a"]#这里应该加上双引号,否则 -n $a 的结果永远是 true!!!$ 检测字符串是否为空,不为空返回 true。[$a]

12、文件测试运算符

-b file 检测文件是否是块设备文件,如果是,则返回 true。
-c file 检测文件是否是字符设备文件,如果是,则返回 true。
-d file 检测文件是否是目录,如果是,则返回 true。
-f file 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true。
-g file 检测文件是否设置了 SGID 位,如果是,则返回 true。
-k file 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true。
-p file 检测文件是否是有名管道,如果是,则返回 true。
-u file 检测文件是否设置了 SUID 位,如果是,则返回 true。
-r file 检测文件是否可读,如果是,则返回 true。
-w file 检测文件是否可写,如果是,则返回 true。
-x file 检测文件是否可执行,如果是,则返回 true。
-s file 检测文件是否为空(文件大小是否大于0),不为空返回 true。
-e file 检测文件(包括目录)是否存在,如果是,则返回 true。
-S: 判断某文件是否 socket。
-L: 检测文件是否存在并且是一个符号链接。

13、echo

echo“”>文件路径#清空文件echo“test”>文件路径#清空文件写入字符echo“test”>>文件路径#追加<重定向输入某个位置文件2>重定向错误输出2>>重定向错误追加输出到文件末尾&>混合输出错误的和正确的都输出

14、输入/输出重定向

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 之间的内容作为输入。

需要注意的是文件描述符 0 通常是标准输入(通常是键盘),1 是标准输出(通常是屏幕),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

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

15、printf

printf 中可格式化字符串,还可以制定字符串的宽度、左右对齐方式等。
默认printf不会像echo自动添加换行符,我们可以手动添加 \n

16、test

test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

17、流程控制

ifconditionthencommandfiforvarinitem1 item2... itemNdocommanddonewhileconditiondocommanddoneuntilconditiondocommanddonecase值in模式1)command1;;模式2) command2;;esac

break命令允许跳出所有循环(终止执行后面的所有循环)
continue命令与break命令类似,只有一点差别,它不会跳出所有循环,仅仅跳出当前循环。

18、let

let 命令是 BASH 中用于计算的工具,用于执行一个或多个表达式,变量计算中不需要加上 $ 来表示变量。如果表达式中包含了空格或其他特殊字符,则必须引起来。
如自加操作:let no++

19、函数

[function]funname[()]{action;[return int;]}

可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。

20、操作键盘输入

read-p"请输入一段文字:"-n6-t5-spasswordecho-e"\npassword is$password"

提示:-p 输入提示文字
-n 输入字符长度限制(达到6位,自动结束)
-t 输入限时
-s 隐藏输入内容,将输入文本颜色设置为与背景色一样
read命令中,可根据需要将输入的数据保存在多个变量中,如指定的变量比较少,那么最后一个变量将包含余下的所有输入。如使用read命令时不指定变量,那么read将其接收的任何数据都放到环境变量REPLY中。

使用read命令时,脚本会一直等待用户输入数据,如果想设置等待时间,使用-t选项即可指定一个计时器,当计时器超时后,read命令会返回一个非零状态码。

ifread-t5-p"Please enter your name: "namethenecho"Hello$name."elseecho"Sorry, too slow"fi

read每次从文件中读取一行数据,当文件中没有数据时,read命令返回非零状态码。最常见的方法是将cat命令运行后的结果通过管道传给含有read的while语句。

count=1cat25.sh|whilereadlinedoecho"Line$count:$line"count=$[$count+1]done

21、select与case

#!/bin/bash# sh解释器不支持select, bash支持;# 1、将解释器定为bash 2、运行时使用bash或者source命令运行脚本fruits=("apple""pear""orange")selectvarin${fruits[@]};doecho"You have selected$var"case"$var"in"apple"*)echo"apple";;"pear"*)echo"pear";;"orange"*)echo"orange";;*)echo"File$1can not be uncompressed with smartzip";;esacif[$var="pear"];thenecho"sorry! you like pear."break# 没有遇到break不会退出选择循环fidone

22、多命令逻辑执行顺序

A.分号 ;
command1 ; command2
命令之间没有逻辑关系。分号连接的命令会按照顺序从前向后依次执行,但分号两端的命令之间没有任何逻辑关系,所有写出来的命令最终都会被执行,即使分号前面的命令出错也不影响后面的命令。

B.&&
command1 && command2
逻辑与。&&连接的命令会按照顺序从前向后执行,但只有当command1正确执行才执行command2,如果command1不正确执行,则不执行command2。在bash中,通过预定义变量“? ”来判断命令是否正确执行,如果 " ?”来判断命令是否正确执行,如果"?”来判断命令是否正确执行,如果"?"的值为0则表示前一条命令正确执行,其他任意值都表示不正确执行。

C.||
command1 || command2
逻辑或。||连接的命令会按照顺序从前向后执行,但只有当command1不正确执行才执行command2,command1正确执行则不会执行command2。||和&&都是短路符号,符号左右的命令之间具有逻辑关系。

D.&
command1 &
command1 & command2
&表示将其前面的命令放入后台执行,放入后台后会立即返回到bash环境让用户可以继续和bash交互。如果&符号连接了两个命令,则其前面的命令被放入后台,立即执行后面的命令,所以可以简单地认为这两个命令是并行执行的,两端的命令之间也没有任何逻辑关系。
需要注意的一点是,在终端的bash环境下,子shell中的后台的进程不受终端控制,在终端被关闭时它会挂靠在init/systemd进程下,因此退出终端或脚本shell环境,无法中断这些后台进程。

23、包含外部脚本

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

#!/bin/bash#使用 . 号来引用test1.sh 文件../test1.sh# 注意点号.和文件名中间有一空格# 或者使用以下包含文件代码# source ./test1.sh# 被包含的文件 test1.sh 不需要可执行权限。

24、获取进程ID

shell获取进程ID的方法:
a、ps -A |grep “cmdname”| awk ‘{print $1}’
b、pidof “cmdname”
c、pgrep “cmdname”
这三种在bash和busybox ash里面的运行结果稍有不同:
第一种完全相同,但是因为调用命令次数较多,性能上是不行的。
第二种:pidof只能获取程序的文件名匹配到的进程号,在ash中比如 pidof “usr/bin/telnetd” 和 pidof "telnetd"中结果不一样,前一种结果为空,但是在bash中执行两者一样。
第三种:pgrep跟1的效果相同,因为是单一命令,比第一种性能要好得多。

25、杀进程

kill [options] <pid> pkill processname

26、xargs

xargs是给命令传递参数的一个过滤器,也是组合多个命令的一个工具。
xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。
xargs 也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。
xargs 默认的命令是 echo,这意味着通过管道传递给 xargs 的输入将会包含换行和空白,不过通过 xargs 的处理,换行和空白将被空格取代。
xargs 是一个强有力的命令,它能够捕获一个命令的输出,然后传递给另外一个命令。
由于很多命令不支持|管道来传递参数,而日常工作中有有这个必要,所以就有了 xargs 命令
https://www.runoob.com/linux/linux-comm-xargs.html

27、chattr

chattr命令用于改变文件属性。

改变存放在ext2文件系统上的文件或目录属性,共有以下8种模式:
a:让文件或目录仅供附加用途。
b:不更新文件或目录的最后存取时间。
c:将文件或目录压缩后存放。
d:将文件或目录排除在倾倒操作之外。
i:不得任意更动文件或目录。
s:保密性删除文件或目录。
S:即时更新文件或目录。
u:预防意外删除。
参数
-R 递归处理,将指定目录下的所有文件及子目录一并处理。
-V 显示指令执行过程。
+<属性> 开启文件或目录的该项属性。
-<属性> 关闭文件或目录的该项属性。

例:用chattr命令防止系统中某个关键文件被修改:chattr +i /etc/resolv.conf
查看:lsattr /etc/resolv.conf

28、自动输入sudo的密码

echo “admin” | sudo -S service tomcat7 stop
参考:link
expect待学习


本文内容参考公开技术文档,如有侵权请联系删除。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询