1. 简介
Shell俗称壳程序,是一种由C语言编写的用于和操作系统交互的命令解析器软件。它用来接收用户输入命令,然后调用相应的应用程序。
Shell 是一种脚本语言,常见的 Shell 脚本解释器有 bash、sh、csh、ash、ksh、tcsh、zsh等几种。
查看系统支持的shell列表:
cat /etc/shells
查看当前系统使用的Shell:
echo $SHELL
2. Shell 变量
变量的定义规则:
- 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
- 中间不能有空格,可以使用下划线(_)。
- 不能使用标点符号。
- 不能使用bash里的关键字(可用help命令查看保留关键字)。
1. 定义变量
1. 变量中的引号
- 单引号:单引号里面是什么就输出什么;
- 双引号:输出时会先解析里面的变量和命令;
- 反引号:动态变量,可根据命令执行将结果直接付给定义的变量。
2. 变量定义
四种定义变量的方式:
variable=value # 普通变量:不包含任何空白符(例如空格、Tab缩进等)
variable='value' # 单引号:里面是什么就输出什么
variable="value" # 双引号:会解析里面的变量和命令
variable=`value` # 反引号:返回执行的结果
2. 使用变量
1. 环境变量
使用 set 命令显示当前环境变量列表:
$ set
...
2. 用户变量
- 变量名前添加$符合使用用户变量
your_name="linux265"
echo $your_name
echo ${your_name}
加花括号是为了帮助解释器识别变量的边界。推荐给所有变量加上花括号。
- 动态变量,可根据命令执行将结果直接付给定义的变量。
有两种方法可以将命令输出赋给变量: -
- 反引号字符(`)——ESC 键下边;
-
- $() 格式;
实例:
date_str_1=`date`
date_str_2=$(date)
通过echo输出的date_str_1和date_str_2结果一样都是:Wed Mar 15 23:10:24 CST 2023
3. Shell数组
Shell数组只支持一维数组,并且不用限定数组大小。下标都是从0开始。
1. 定义数组
- 使用()表示数组
arrs=(one two three four five)
- 使用下标表示数
arrs[0]=one
arrs[1]=two
arrs[2]=three
arrs[3]=four
arrs[4]=five
下标数可以任意指定,范围没有限制,而且下标不是必须连续。
2. 读取数组
- 读取某个元素
${array_name[index]}
- 读取全部元素——使用特殊符号*和@
echo $arrs[*]
echo $arrs[@]
输出结果:one two three four five
3. 获取数组长度
获取数组长度:
len=${#arrs}
len=${#arrs[*]}
len=${#arrs[@]}
获取具体元素的长度:
len=${#arrs[n]}
4. 删除数组中的元素
通过unset删除:
unset arrs[n]
删除整个数组:
unset arrs
5. 拼接数组
使用@和*来获取数组的全部元素,然后将两个数组拼接到一起。
实例:
#!/bin/bash
arr1=(1 2 3 4 5 qq)
arr2=(6 7 8 9 10 wechat)
arr3=(${arr1[@]} ${arr2[@]})
echo ${arr3[@]}
结果:
1 2 3 4 5 qq 6 7 8 9 10 wechat
4. Shell运算符
- 算数运算符
- 关系运算符
- 布尔运算符
- 字符串运算符
- 文件测试运算符
原生bash不支持简单的数学运算,可以通过 let 和 expr 实现,其中 expr 最常用。
实例(注意使用的是反引号 ` 而不是单引号 '):#!/bin/bash val=`expr 1 + 2` # 表达式和运算符之间要有空格 echo "两数之和为 : $val"
输出结果如下所示:
两数之和为 : 3
1. 算术运算符
常用算术运算符:
运算符 | 举例 |
---|
- | expr $a + $b
- | expr $a - $b
- | expr $a * $b
/ | expr $b / $a
% | expr $b % a = ∣ a = a = | a= a=∣a=b 赋值
== | [ $a == $b ] 返回 false
!= | [ $a != $b ] 返回 true
注意:条件表达式要放在方括号之间,并且要有空格
实例:
#!/bin/bash
a=10
b=20
val=`expr $a + $b`
echo "a + b : $val"
val=`expr $a - $b`
echo "a - b : $val"
val=`expr $a \* $b`
echo "a * b : $val"
val=`expr $b / $a`
echo "b / a : $val"
val=`expr $b % $a`
echo "b % a : $val"
if [ $a == $b ]
then
echo "a 等于 b"
fi
if [ $a != $b ]
then
echo "a 不等于 b"
fi
输出结果:
a + b : 30
a - b : -10
a * b : 200
b / a : 2
b % a : 0
a 不等于 b
2. 关系运算符
关系运算符只支持数字,不支持字符串,除非字符串的值是数字。
假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
-eq | 相等 | [ $a -eq $b ] 返回 false |
-ne | 不相等 | [ $a -ne $b ] 返回 true |
-gt | 大于 | [ $a -gt $b ] 返回 false |
-lt | 小于 | [ $a -lt $b ] 返回 true |
-ge | 大于等于 | [ $a -ge $b ] 返回 false |
-le | 小于等于 | [ $a -le $b ] 返回 true |
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. 逻辑运算符
假定变量 a 为 10,变量 b 为 20:
运算符 | 说明 | 举例 |
---|---|---|
&& | 逻辑的 AND | [[ $a -lt 100 && $b -gt 100 ]] 返回 false |
逻辑的 OR |
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。 |
6. 文件测试运算符
操作符 | 说明 |
---|---|
-b file | 检测文件是否是块设备文件。 |
-c file | 检测文件是否是字符设备文件。 |
-d file | 检测文件是否是目录。 |
-f file | 检测文件是否是普通文件(既不是目录,也不是设备文件。 |
-g file | 检测文件是否设置了 SGID 位。 |
-k file | 检测文件是否设置了粘着位(Sticky Bit)。 |
-p file | 检测文件是否是有名管道。 |
-u file | 检测文件是否设置了 SUID 位。 |
-r file | 检测文件是否可读。 |
-w file | 检测文件是否可写。 |
-x file | 检测文件是否可执行。 |
-s file | 检测文件是否为空(文件大小是否大于0)。 |
-e file | 检测文件(包括目录)是否存在。 |
-S file | 判断某文件是否 socket。 |
-L file | 检测文件是否存在并且是一个符号链接。 |
5. Shell结构命令
1. if-else
1. if
语法格式:
if condition
then
command1
command2
...
commandN
fi
实例,写成一行(适用于终端命令提示符):
if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
2. if else
语法格式:
if condition
then
command1
command2
...
commandN
else
command
fi
3. if elif else fi
语法格式:
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
实例:
a=10
b=20
if [ $a == $b ]
then
echo "a 等于 b"
elif [ $a -gt $b ]
then
echo "a 大于 b"
elif [ $a -lt $b ]
then
echo "a 小于 b"
else
echo "没有符合的条件"
fi
输出结果:
a 小于 b
2. 多选择已经
case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
esac
case工作方式:
- 取值后面必须为单词in,每一模式必须以右括号结束;
- 取值可以为变量或常数
- 匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;
如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
实例:
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
3. 循环
1. for 循环
for循环一般格式为:
for var in item1 item2 ... itemN
do
command1
command2
...
commandN
done
写成一行:
for var in item1 item2 ... itemN; do command1; command2… done;
实例:
for loop in 1 2 3 4 5
do
echo "The value is: $loop"
done
输出结果:
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
2. while 循环
while condition
do
command
done
实例:
#!/bin/bash
int=1
while(( $int<=5 ))
do
echo $int
let "int++"
done
输出:
1
2
3
4
5
3. 跳出循环
使用命令:break和continue。
- break命令允许跳出所有循环(终止执行后面的所有循环)。
- continue命令仅仅跳出当前循环。
实例:
#!/bin/bash
while :
do
echo -n "输入 1 到 5 之间的数字: "
read aNum
case $aNum in
1|2|3|4|5) echo "你输入的数字为 $aNum!"
;;
*) echo "你输入的数字不是 1 到 5 之间的!"
continue
echo "游戏结束"
;;
esac
done
6. Shell函数
1. 函数定义
函数定义格式:
[ function ] funname [()]
{
action;
[return int;]
}
说明:
- 可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
- 参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
2. 带有return语句的函数
实例:
#!/bin/bash
function funWithReturn()
{
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
funWithReturn
echo "输入的两个数字之和为 $? !"
输出:
-->$ ./test.sh
这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
12
输入第二个数字:
3
两个数字分别为 12 和 3 !
输入的两个数字之和为 15 !
通过 $? 获取函数返回值。
注意:所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。调用函数仅使用其函数名即可。
3. 函数参数
在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$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
输出:
第一个参数为 1 !
第二个参数为 2 !
第十个参数为 10 !
第十个参数为 34 !
第十一个参数为 73 !
参数总数有 11 个!
作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !
注意, 10 不能获取第十个参数,获取第十个参数需要 10 不能获取第十个参数,获取第十个参数需要 10不能获取第十个参数,获取第十个参数需要{10}。当n>=10时,需要使用${n}来获取参数。
特殊字符用来处理参数:
参数处理 | 说明 |
---|---|
$# | 传递到脚本或函数的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
7. Shell输入/输出重定向
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 之间的内容作为输入。 |
注意: 文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。
2. 输出重定向
语法:
command1 > file1 # 追加使用 >>
示例:
who > tt.txt
3. 输入重定向
语法:
command1 < file1
需要从键盘获取输入的命令会转移到文件读取内容。
示例:
-->$ cat tt.txt | wc
2 10 109
-->$
-->$ wc < tt.txt
2 10 109
4. 重定向理解
一般情况下,每个 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 # 追加使用 >>
- 希望将 stdout 和 stderr 合并后重定向到 file
command > file 2>&1
或者
command >> file 2>&1
希望对 stdin 和 stdout 都重定向:
command < file1 > file2 # file1 作为输入,结果输出到file2
5. /dev/null 文件
执行某个命令,屏幕上不显示输出结果,可以将输出重定向到 /dev/null:
command > /dev/null
/dev/null 是一个特殊的文件,写入到它的内容都会被丢弃。
/dev/null 文件非常有用,使用2>/dev/null可以不显示错误输出。示例:
-->$ find . -name tt
... 大量报错
-->$ find . -name tt 2>/dev/null
... 只显示查找到的文件