Shell
一、 Shell基础
1. 概述
Shell 是一个用C语言编写的程序,它是用户使用Linux的桥梁。Shell既是一种命令语言,也是一种程序设计语言。
用户通过 Shell 提供的界面访问操作系统内核的服务。
Shell 是一种解释型语言。这种语言经过编写后不经过任何编译就可以执行,是一种脚本语言。和编译型语言是执行前翻译不同,解释型语言的程序是执行时翻译,所以效率要差一 些。
2. Shell种类
cat /etc/shells
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/usr/bin/fish
/usr/local/bin/fishlogin
3. Shell工作模式
3.1 互动模式
3.2 脚本模式
vim helloWorld.sh
# 写入以下内容
#!/bin/bash
# 是一个标记,告诉系统执行这个文件需要的解释器
# this line is a comment “#”号开头的行代表注释
echo "Hello World"
# 脚本运行
bash helloWorld.sh
# “.”号和source命令也都可以执行脚本,且不需要可执行权限
. helloWorld.sh
# source在当前bash环境下读取并执行FileName中的命令
source helloWorld.sh
# 给脚本添加可执行权限,然后直接就可以执行了
chmod o+x helloWorld.sh
./helloWorld.sh
4. 变量
变量就是其值可以变化的量。从变量的本质来说,变量名是指向一片用于存储数据的内存空间。变量分为变量有局部变量、环境变量(全局变量)。在脚本中,往往需要使用变量来存储有用信息,比如文件名、路径名、数值等,通过这些变量可以控制脚本的运行行为。
4.1 局部变量
是指在某个shell中生效的变量,对其他shell来说无效,局部变量的作用域被限定在声明它们的shell中,可以使用local内建命令来“显式”的声明局部变量,但仅限于函数内使用。
4.2 环境变量
环境变量通常又称“全局变量”,以区别于局部变量。在shell脚本中,变量默认就是全局的,为了让子shell继承当前shell的变量,可以使用export命令将其定义为环境变量。
4.3 bash默认预设环境变量
-
bash中默认包含有几十个预设的环境变量。下面介绍一些常用的:
# BASH: Bash shell的全路径 echo $BASH # BASH_VERSION : bash shell的版本 echo $BASH_VERSION # EUID:记录当前用户的UID echo $EUID # FUNCNAME:在用户函数体内部,记录当前函数体的函数名。 vim funcname.sh # 写入以下内容 #!/bin/bash funcname() { echo $FUNCNAME } # 运行 . funcname.sh # HISTCMD:记录下一条命令在history命令中的编号 # HISTFILE:记录history命令记录文件的位置 # HISTFILESIZE:设置HISTFILE文件记录命令的行数 # HISTSIZE:设置命令缓冲区的大小 # HOSTNAME:设置主机名 # HOSTTYPE:展示主机的架构 # MACHTYPE:主机类型的GNU标识,这种标识有统一的结构。一般来说是“主机架构-公司-系统-gnu” # LANG:设置当前系统的语言环境 # PWD:记录当前目录 # OLDPWD:记录之前目录 # PATH:代表命令的搜索路径,非常重要
4.4 变量名
shell中的变量必须以字母或者下划线开头,后面可以跟数字、字母和下划线,长度没有限制,区分大小写。
4.5 变量赋值和取值
# 变量赋值
# 注意点1:变量名和变量值之间用等号紧紧相连,之间没有任何空格
name=john
# 注意点2:当变量值中有空格时必须用引号括起,否则会出现错误,可以是双引号,也可以是单引号
name="li si"
# 变量取值
echo $name
# 严谨的方法是${}
echo ${name}
# 取消变量 unset后面也是可以跟上函数名来取消函数
unset name
4.6 特殊变量
-
位置参数
-
$0:代表脚本本身名字
-
$1----$9:第一个位置参数-------第9个位置参数
-
$#:脚本参数的个数总和
-
$@:表示脚本的所有参数
-
$* :表示脚本的所有参数
vim posion.sh # 写入以下内容 #!/bin/bash echo "这个脚本的名字是:$0" echo "参数一共有$#" echo "参数的列表是: $@" echo "参数的列表是: $*" echo "第一个参数是: $1" echo "第二个参数是: $2" echo "第三个参数是:$3" # 调用测试 . posion.sh a b c
-
-
脚本或者命令返回值:$?
-
正常退出的命令和脚本应该返回值为0,任何非0的返回值都表示命令未正确退出或未正常执行。
ifcofj echo $? ping -c 1 www.baidu.com echo $?
-
5. 数组
-
概述
数组是一种特殊的数据结构,其中的每一项被称为一个元素,对于每个元素,都可以用索引的方式取出元素的值。使用数组的典型场景是一次性要记录很多类型相同的数据时(但不一定必须要相同)。比如,为了记录班级中所有人的数学成绩,如果不用数据来处理,那就只能定义所有人成绩的变量。shell中的数组对元素个数没有限制,但只支持一维数组。
-
使用
# 使用declare [dɪˈkler] (公布; 宣布; 宣告; 表明)命令定义数组Array # declare [+/-][rxi][变量名称=设置值] 或 declare -f # +/- "-"可用来指定变量的属性,"+"则是取消变量所设的属性。 # -f 仅显示函数。 # -a 将变量var声明为数组变量。 # r 将变量设置为只读。 # x 指定的变量会成为环境变量,可供shell以外的程序来使用。 # i [设置值]可以是数值,字符串或运算式。 declare -a Array Array[0]=0 Array[1]=1 Array[2]="HelloWorld" # 也可以在创建的同时赋值 declare -a Name=('john' 'sue') Name[2]='wang' # 更简单的方式来创建数组 Name=('john' 'sue') # 还可以跳号赋值 Score=([3]=3 [5]=5 [7]=) # 数组操作 # 数组取值:格式为:${数组名[索引]} echo ${Array[0]} echo ${Array[2]} echo ${Name[1]} # 一次性取出数组所有的值 # 得到的是以空格隔开的元素值 echo ${Array[@]} # 输出的是一整个字符串 echo ${Array[*]} # 数组长度:即数组元素个数 # 利用“@”或“*”字符,可以将数组扩展成列表,然后使用“#”来获取数组元素的个数。 echo ${#Array[*]} echo ${#Array[@]} # 数组截取 可以截取某个元素的一部分,对象可以是整个数组或某个元素。 # 取出数组的第一个、第二个元素 echo ${Array[@]:1:2} # 取出第二个元素从第0个字符开始连续5个字符 echo ${Array[2]:0:5} # 连接数组:将若干个数组进行拼接操作 Conn=(${Array[@]} ${Name[@]}) echo ${Conn[@]} # 替换元素:将数组内某个元素的值替换成其他值 Array=(${Array[@]/HelloWorld/HelloJohn}) echo ${Array[@]} # 取消数组或元素:使用unset命令 unset Array[1] echo ${Array[@]} unset Array echo ${Array[@]}
5.1 只读变量
-
只读变量又称常量,通过readonly内建命令创建,创建时需要赋值,并且之后无法修改。
readonly RO=100 RO=200
6. 转义和引用
6.1 转义
-
shell中有很多特殊字符,会有特殊意义,但是有时候会造成麻烦,需要转义才可以使用,转义符号为“\”
echo 8 \* 8 =64 echo \$Dollar
6.2 引用
-
引用是指将字符串用某种符号括起来,以防止特殊字符被解析为其他意思。
-
shell中一共有4种引用符,分别为双引号、单引号、反引号和转义符。
-
双引号可以引用除$符号、反引号、转义符之外的所有字符;单引号可以引用所有字符;反引号则会将反引号中的内容解释为系统命令。
echo "current directory is $PWD" echo 'current directory is $PWD' # 命令替换:是指将命令的标准输出作为值赋给某个变量。 # 格式有反引号和$(),建议使用$() TIME=`date +%F` echo $TIME TIME2=$(date +%F) echo $TIME2
7. 运算符
7.1 概述
shell中的运算符主要有比较运算符(用于整数比较)、字符串运算符(用于字符串测试)、文件操作运算符(用于文件测试)、逻辑运算符、算术运算符、位运算符、自增自减运算符等。
7.2 算数运算符
-
概述
算术运算符指的是加、减、乘、除、余、幂等常见的算术运算,以及加等、减等、乘等、除等、余等复合算术运算。要特别注意的是,shell只支持整数计算,也就是说所有可能产生小数的运算都会舍去小数部分。
-
使用
# Bash shell 的算术运算有四种方式: # 1:使用 expr 外部程式 注意! '4' '+' '5' 这三者之间要有空白 r=`expr 4 + 5` echo $r r=`expr 4 \* 5` echo $r # 2:使用 $(( )) r=$(( 4 + 5 )) echo $r # 3:使用 $[ ] r=$[ 4 + 5 ] echo $r # 乘法 r=$(( 4 * 5 )) r=$[ 4 * 5 ] echo $r # 除法 r=`expr 40 / 5` r=$(( 40 / 5 )) r=$[ 40 / 5 ] echo $r # 减法 r=`expr 40 - 5` r=$(( 40 - 5 )) r=$[ 40 - 5 ] echo $r # 求余数 r=$[ 100 % 43 ] echo $r # 乘幂 (如 2 的 3 次方) r=$(( 2 ** 3 )) r=$[ 2 ** 3 ] echo $r # !! expr 沒有乘幂 !! # 4:使用 let 命令 # 加法: n=10 let n=n+1 echo $n # 乘法: let m=n*10 echo $m # 除法: let r=m/10 echo $r # 求余数: let r=m%7 echo $r # 乘冪: let r=m**2 echo $r # !! 虽然Bash shell 有四种算术运算方法,但并不是每一种都是跨平台的,建议使用expr。 !! # 另外,我们在 script 中经常有加1操作,以下四法皆可: m=$[ m + 1] m=`expr $m + 1` m=$(($m + 1)) let m=m+1
7.3 位运算符
-
位运算符是基于内存中二进制数据的运算,也就是基于位的运算。
# 位运算的左移、右移元素其实就是整数在内存中的“左右移动”。其中左移运算符为<<,右移运算符为>>。 let "a=4<<2" echo $a let "b=4>>2" echo $b # 按位与运算(&),也就是取小,只有对应的二进制值都为1的时候,结果才为1 let "c=192&255" echo $c # 按位或运算(|),是将两个整数写成二进制的形式,然后同位置相比较,只要对应的位 置有1,结果就是1。 let "d=8|4" echo $d # 按位异或运算(^),是将两个整数写成二进制的形式,然后同位置比较,只要相同,结果为0,否则为1。 let "e=10^3" echo $e
7.4 自增自减
-
概述
增自减运算主要包括前置自增、前置自减、后置自增、后置自减等。前置自增或 自减操作会首先修改变量的值,然后再将变量的值传递出去;后置自增或后置自减则会首先 将变量的值传递出去,然后再修改变量的值。自增符号为“++”,自减符号为“--”,操作 对象只能是变量,不能是常数或表达式。
-
使用
Add_01=10 Add_02=10 # 前置自增 let Add_03=(++Add_01) echo $Add_03 echo $Add_01 #后置自增 let Add_04=(Add_02++) echo $Add_04 echo $Add_02
8. 特殊字符
8.1 通配符
通配符用于模式匹配,常见的通配符有\*、?和用[]括起来的字符序列。
\*:代表任意长度的字符串。例如:a\*可以匹配以a开头的任意长度的字符串,但是不包括点号和斜线号。也就是说a\*不能匹配abc.txt
?:用于匹配任一单个字符。
\[ ]: 代表匹配其中的任意一个字符,比如[abc]代表匹配a或则b或则c,[ ]中可以用“-”表明起止,比如[a-c]等同于[abc]。\*和?在\[ ]中则变成了普通字符,没有通配的功效。
8.2 引号:包括单引号和双引号
双引号中的字符除了“$”、“\”、反引号依然保留其特殊用途外,其余字符都作为普通字符处理。 单引号中的字符都作为普通字符处理 。
8.3 注释符
"#"代表注释,除了”#!“,其表示某个解释器的路径,且必须在整个脚本的第一行。
8.4 大括号
- 变量扩展。引用变量,例如变量VAR,可以使用${VAR}引用。
echo {x1,x2,x3}{y1,y2,y3}
echo file{1..6}
echo file{4,8,9}
8.5 控制字符
控制字符即ctrl+key组合键一起使用,用于修改终端或文本显示。控制字符是交互式使用的,不能用于脚本中。
8.6 感叹号
通常代表逻辑反,例如 != 表示不等于。
9. 重定向
9.1 概述
计算机最基础的功能是可以提供输入输出操作。对于Linux系统来说,通常以键盘为默 认输入设备,又称标准输入设备;以显示器为默认的输出设备,又称标准输出设备。所谓重 定向,就是将原本应该从标准输入设备(键盘)输入的数据,改由其他文件或设备输入,或 将原本应该输出到标准输出设备(显示器)的内容,改由输出到其他文件或设备上。
9.2 文件标识符
文件标识符是重定向中很重要的一个概念,Linux使用0到9的整数指明了与特定进程相 关的数据流,系统在启动一个进程的同时会为该进程打开三个文件:标准输入(stdin)、 标准输出(stdout)、标准错误输出(stderr),分别用文件标识符0、1、2来标识。如果 要为进程打开其他的输入输出,则需要从整数3开始标识。默认情况下,标准输入为键盘, 标准输出和错误输出为显示器。 std = standard [ˈstændərd] (标准)
ll /dev/stdin
ll /dev/stdout
ll /dev/stderr
9.3 I/O重定向符号和用法
-
I/O重定向可以将任何文件、命令、脚本、程序的输出重定向到另外一个文件、命令、程序或脚本。
# 显示当前目录文件 test.sh test1.sh test1.sh实际不存在 touch test.sh ls test.sh test1.sh # 输出重定向 # 把正确输出写入suc.txt 自动创建suc.txt ls test.sh test1.sh > suc.txt cat suc.txt # 把错误输出,不输出到屏幕,输出到err.txt ls test.sh test1.sh > suc.txt 2> err.txt # 继续追加把输出写入suc.txt err.txt “>>”追加操作符 ls test.sh test1.sh >> suc.txt 2>> err.txt # 将错误输出信息关闭掉 # &[n] 代表是已经存在的文件描述符,&1 代表输出 &2代表错误输出 &-代表关闭与它绑定的描述符 # Linux系统将所有设备都当作文件来处理,而Linux用文件描述符来标识每个文件对象。 # 内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。 # 打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。 ls test.sh test1.sh 2>&- # 将错误输出信息输出到黑洞 ls test.sh test1.sh 2>/dev/null # 关闭所有输出 # 关闭 1 ,2 文件描述符 ls test.sh test1.sh 1>&- 2>&- # 将1,2 输出转发给/dev/null设备 ls test.sh test1.sh 1>/dev/null 2>/dev/null # 将错误输出2 绑定给 正确输出 1,然后将 正确输出 发送给 /dev/null设备 这种常用 # !!1>/dev/null 2>&1顺序很重要!! ls test.sh test1.sh 1>/dev/null 2>&1 ls test.sh test1.sh &>/dev/null # PS: 默认控制输出重定向为1 可以省略不写。 # 例: ls test.sh test1.sh 1>/dev/null 2>&1 等价于 ls test.sh test1.sh >/dev/null 2>&1 # 输入重定向 # EOF 通常与 << 结合使用,<<EOF 表示后续的输入作为子命令或子shell的输入,直到遇到 EOF cat > a.txt << EOF > hello world > EOF cat a.txt
9.4 管道符 |
管道表现为输入输出重定向的一种方法,可以将一个命令的输出内容当做下一个命令的输入内容,可以通过多个简单命令的共同协作来完成较为复杂的工作。
ll /etc | less
二、 测试和判断
1. 测试结构
1.1 文件测试
1.test expression
2.[ expression ]
# expression为表达式
1.2 字符串测试
-
shell中的字符串比较主要有等于、不等于、大于、小于、是否为空等测试。
-n string 若string的长度不为0,则为真,否则为假 -z string 若string的长度为0,则为真,否则为假 string1 = string2 若string1等于string2,则为真,否则为假 string1 != string2 若string1不等于string2,则为真,否则为假 string1 > string2 若string1排在string2之前则为真,否则为假 string1 < strint2 若string1排在string2之后则为真,否则为假
1.3 整数比较
-
整数测试是一种简单的算术运算,作用在于比较两个整数的大小关系,测试成立则返回
-eq 等于 -gt 大于 -lt 小于 -ge 大于等于 -le 小于等于 -ne 不等于
1.4 逻辑测试符
-
逻辑测试用于连接多个测试条件,并返回整个表达式的值。
-
逻辑测试主要有逻辑非、逻辑与、逻辑或3种
# 非(!)、与(-a)、或(-o) ! expression 如果expression为真,则测试结果为假 expressionl -a expression2 expressionl和expression2同时为真,则测试结果为真 expression1 -O expression2 expressionl和expression2只要有一-个为真,则测试结果为真
-
实例
# 逻辑非 [root@bzx ~]# [ ! -e /var/log/messages ] [root@bzx ~]# echo $? 1 # 逻辑与 [root@sunday-test ~]# [ -e /var/log/messages -a -e /var/log/messages01 ] [root@sunday-test ~]# echo $? 1 # 逻辑或 [root@sunday-test ~]# [ -e /var/log/messages -o -e /var/log/messages01 ] [root@sunday-test ~]# echo $? 0
-
shell中的逻辑运算符,也有逻辑非、逻辑与、逻辑或 3种
! 逻辑非,对真假取反. && 逻辑与,连接两个表达式,只有两个表达式为真结果才为真 || 逻辑或,连接两个表达式,只要有一个表达式为真结果就为真
三、判断语句
1. If语句
# if判断结构
if expression; then
command
fi
# if/else判断结构
if expression; then
command
else
command
fi
# if/elif/else判断结构
if expression1;then
command1
elif expression2; then
command2
elif expression3 ; then
command3
...
fi
2. case语句
# case判断结构
case VAR in
var1) command1 ;;
var2) command2 ;;
var3) command3 ;;
...
*) command4 ;;
esac