概述

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。

Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。
由于习惯的原因,简洁起见,本文出现的 “shell编程” 都是指 shell 脚本编程,不是指开发 shell 自身。

1
2
3
#!/bin/bash

echo "Hello World!"

变量

详细请参照教程:Shell 变量 | 菜鸟教程

常用系统变量

作用域决定了变量能够影响到的是整个系统还是单个用户

  • $HOME
  • $PWD
  • $SHELL
  • $USER

运算

定义变量时无法对数值进行运算。

1
2
3
[root@ahost Desktop]# result=1*2
[root@ahost Desktop]# echo $result
1*2

只读变量

1
2
3
4
5
6
[root@ahost Desktop]# rov1="hello"
[root@ahost Desktop]# readonly rov1
[root@ahost Desktop]# echo rov1
rov1
[root@ahost Desktop]# rov1="world"
-bash: rov1: readonly variable

删除变量

1
2
3
4
5
6
7
8
[root@ahost Desktop]# dv1="hello"
[root@ahost Desktop]# echo $dv1
hello
[root@ahost Desktop]# unset dv1
[root@ahost Desktop]# echo $dv1

[root@ahost Desktop]#

unset不能删除只读变量。

自定义变量

1
2
# 定义变量时,变量名不加美元符号
str="Hello World!"

使用变量时可用花括号标注变量名是$str而非$strWorld,从而避免意料外的情况。

1
2
3
4
5
str="Hello,"

echo "$strWorld!"

echo "${str}World!"

变量名和等号之间不能有空格

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线 **_**。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

特殊变量:$n

$n:其中 n 通常为 1-9 中的任意一个数字。

1
2
3
4
5
6
#!/bin/bash

# 输出参数的值
echo $1
echo $2
echo $3
1
2
3
4
[root@ahost Desktop]# bash echo.sh a b c
a
b
c

特殊变量:$ #

$#:获取所有输入参数的个数

1
2
3
4
5
6
7
8
9
#!/bin/bash

# 输出参数的总数
echo $#

# 输出参数的值
echo $1
echo $2
echo $3
1
2
3
4
5
[root@ahost Desktop]# bash echo.sh a b c
3
a
b
c

特殊变量:$* 和 $@

$*:代表当前shell中的所有参数,并将参数看作一个整体
$@:同$*,但对参数

1
2
3
4
5
6
7
8
9
#!/bin/bash

# 输出参数的总数
echo $#

# 输出参数的值
echo $1
echo $2
echo $3

特殊变量:$?

$?:最后一次执行的命令的返回状态,0为命令被正确执行,反之。
执行正常:

1
2
3
4
[root@ahost Desktop]$ ls
1.txt 2.txt echo.sh helloworld.sh
[root@ahost Desktop]# echo $?
0

没有权限:

1
2
3
4
[java@ahost Desktop]$ cat /etc/shadow
cat: /etc/shadow: Permission denied
[java@ahost Desktop]$ echo $?
130

运算符

运算符的基本语法

“$((运算表达式))” or “$[运算表达式]”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#!/bin/bash
X=100
Y=20

# 第一种
A=$((X-Y))
echo $A

# 第二种
B=$[X+Y]
echo $B

# 第三种
C=`expr $X / $Y`
echo $C

# 综合运算 (2+3) * 5
D=$[(2+3)*5]
echo $D

# 综合运算 expr 方法(使用 expr 时,“*”号需要使用反引号进行转义)
expr `expr 2 + 3` \* 5
1
2
3
4
5
6
[root@ahost Desktop]# bash math.sh 
80
120
5
25
25

expr +,-,*,/,%

1
2
3
[root@ahost Desktop]# A=`expr 4 + 4`
[root@ahost Desktop]# echo $A
8

条件判断

条件判断的基本语法

[ condition ] (条件表达式前后需有空格)
注意:条件非空即为true[string]返回true[]返回false

常用判断条件

  1. 整数之间比较

    语法 含义
    = 字符串比较
    -lt 小于(less than)
    -le 小于等于(less equal)
    -eq 等于(equal)
    -gt 大于(greater than)
    -ge 大于等于(greater equal)
    -ne 不等于(Not equal)
  2. 按文件权限进行判断

    语法 含义
    -r 有读权限(read)
    -w 有写权限(wrtie)
    -x 有执行权限(execute)
  3. 按文件类型进行判断

    语法 含义
    -f 文件存在,并且是一个常规文件(file)
    -e 文件存在(existence)
    -d 文件存在,并且是一个目录(directory)

示例

1
2
3
4
5
6
7
#!/bin/bash

# && 逻辑与
[ $# -gt 2 ] && echo "参数个数大于 2"

# || 逻辑或
[ $# -le 2 ] || echo "参数个数大于 2--"
1
2
3
4
5
[root@ahost Desktop]# bash condition.sh 1
[root@ahost Desktop]# bash condition.sh 1 2
[root@ahost Desktop]# bash condition.sh 1 2 4
参数个数大于 2
参数个数大于 2--
1
2
3
4
5
#判断对该文件是否有读权限
[root@ahost Desktop]# [ -r helloworld.sh ]
[root@ahost Desktop]# echo $?
0
# 执行状态 0 即为 true。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 判断指定用户不存在时,添加该用户

[root@ahost Desktop]# cat adduser.sh
id hiyori &> /dev/null && echo "用户已存在"
id hiyori &> /dev/null || useradd hiyori

# 此处判断得出当前系统并没有该用户,根据条件添加
[root@ahost Desktop]# bash adduser.sh

# 此处判断得出该用户已经存在
[root@ahost Desktop]# bash adduser.sh
用户已存在

[root@ahost Desktop]# id hiyori
uid=1001(hiyori) gid=1001(hiyori) groups=1001(hiyori)

流程控制

结尾则以该语句的

if 判断

if 判断的基本语法

1
2
3
4
5
6
7
8
9
if [ 条件语句 ];then
代码...
fi

#或者
if [ 条件语句 ]
then
代码...
fi

注意事项

if [ ]if与中括号之间需要用空格隔开,同理,中括号和条件语句之间也必须有空格;

if 判断的示例

1
2
3
4
5
6
7
8
9
#!/bin/bash

if [ $1 -lt 18 ];then
echo "未成年"
elif [ $1 -ge 18 -a $1 -lt 30 ];then
echo "是青年"
else
echo "中老年"
fi
1
2
3
4
5
6
[root@ahost Desktop]# bash ifage.sh 17
未成年
[root@ahost Desktop]# bash ifage.sh 26
是青年
[root@ahost Desktop]# bash ifage.sh 32
中老年

case 语句

case 语句的基本语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
case $变量名 in
"值1")
代码1...
;;

"值2")
代码2...
;;

"值3")
代码3...
;;

*)
当变量的值不符合上述分支时则执行此段代码...
;;

esac

case 语句的注意事项

  1. case 行尾必须是in,每个分支则必须以右括号)结束;
  2. ;;表示命令序列结束,相当于break
  3. *)代表默认分支,等同于default

case 语句的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#!/bin/bash

case $1 in

"start")
echo "输入的值为 start"
;;

"stop")
echo "输入的值为 stop"
;;

"restart")
echo "输入的值为 restart"
;;

*)
echo "其他内容"
;;

esac
1
2
3
4
5
6
7
8
[root@ahost Desktop]# bash case.sh start
输入的值为 start
[root@ahost Desktop]# bash case.sh restart
输入的值为 restart
[root@ahost Desktop]# bash case.sh stop
输入的值为 stop
[root@ahost Desktop]# bash case.sh status
其他内容

for 循环

for 循环的基本语法

1
2
3
4
5
6
7
8
9
10
# for 和 (( 之间的空格可以省略不写
for ((初始值;循环条件;临时变量))
do
代码...
done

# 或者
for ((初始值;循环条件;临时变量));do
代码...
done

for 循环的扩展语法

1
2
3
4
5
6
7
8
9
for 变量 in 值1 值2 值3 ...
do
代码...
done

# 或者
for 变量 in 值1 值2 值3;do
代码...
done

for 循环的示例

1
2
3
4
5
6
7
8
9
10
11
[root@ahost Desktop]# cat for.sh 
#!/bin/bash

for ((i=0;i<=100;i++));do
sum=$[$sum+$i]
done

echo "从1到100的和是:$sum"

[root@ahost Desktop]# bash for.sh
从1到100的和是:5050
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@ahost Desktop]# cat for2.sh 
#!/bin/bash

# 第一种写法
#for i in {1..100};do

# 第二种写法
for i in `seq 1 100`;do
sum=$[$sum+$i]
done

echo "从1到100的和为:$sum"
[root@ahost Desktop]# bash for2.sh
从1到100的和为:5050

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
[root@ahost Desktop]# cat for3.sh 
#!/bin/bash

for i in `ls /` ;do
echo $i
done
[root@ahost Desktop]# bash for3.sh
bin
boot
dev
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
tmp
usr
var

补充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 特殊变量 $* 和 $@ 的区别
[root@ahost Desktop]# cat for4.sh
#!/bin/bash

# 特殊变量 $*,当该使用引号包裹住变量时,所有参数将被看作一个整体,而特殊变量 $@ 则不受此规则影响
for i in "$*";do
echo "传入脚本的参数为:$i"
done

echo "----------------------------"

# 特殊变量 $@
for j in "$@";do
echo "传入脚本的参数为:$j"
done
[root@ahost Desktop]# bash for4.sh abc def
传入脚本的参数为:abc def
----------------------------
传入脚本的参数为:abc
传入脚本的参数为:def

while 循环

while 循环的基本语法

1
2
3
4
5
6
7
8
9
while [ 条件语句 ]
do
代码...
done

# 或者
while [ 条件语句 ];do
代码...
done

while 循环的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@ahost Desktop]# cat while1.sh 
#!/bin/bash

i=1
sum=0

while [ $i -le 100 ];do
# 等同于 sum=$[$sum+$i]
let sum=sum+i
# let 支持 i++, ++i 等
let i++
done

echo "从1到100的和为:$sum"
[root@ahost Desktop]# bash while1.sh
从1到100的和为:5050

while 循环更适合设定指定条件下的终止循环,也就是对循环流程的控制更为精细化。

读取控制台输入

read 命令

read 命令的基本语法

1
read [选项][参数]
  • -p:指定读取值时的提示符;
  • -t:指定读取值时等待的时间(秒)。
  • 参数:指定读取值的变量名

read 命令的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[root@ahost Desktop]# cat read.sh 
#!/bin/bash

# 从 1 开始到 n 所有数字的和,n 由用户指定

read -p "请输入一个大于 1 的数字:" n

i=1
sum=0
while [ $i -le $n ];do
let sum=sum+i
let i++
done

echo "从 1 到 $n 的和为 $sum"
[root@ahost Desktop]# bash read.sh
请输入一个大于 1 的数字:50
从 1 到 50 的和为 1275
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 添加了 -t 参数来指定允许输入的时间
[root@ahost Desktop]# cat read.sh
#!/bin/bash

# 从 1 开始到 n 所有数字的和,n 由用户指定

read -t 5 -p "请在五秒内输入一个大于 1 的数字:" n

i=1
sum=0
while [ $i -le $n ];do
let sum=sum+i
let i++
done

echo "从 1 到 $n 的和为 $sum"
[root@ahost Desktop]# bash read.sh
请在五秒内输入一个大于 1 的数字:read.sh: line 9: [: 1: unary operator expected
从 1 到 的和为 0

系统函数

basename

basename 的基本语法

basename 的示例

1
2
[root@ahost Desktop]# basename /home/root/Desktop/ifage.sh .sh 
ifage

dirname

dirname 的基本语法

dirname 的示例

1
2
[root@ahost Desktop]# dirname /home/root/Desktop/ifage.sh
/home/root/Desktop

自定义函数

自定义函数的基本语法

1
2
3
4
5
6
7
[ function ] funname [()]
{
action;
[return int;]
}

funname

经验技巧

  1. 必须在调用函数之前声明函数;
  2. 函数返回值只能通过$?获取,且返回值必须是0-255的整数值。

自定义函数的示例

1
2
3
4
5
6
7
8
9
10
11
#!/bin/bash

function sum(){
let s=$1+$2

return $s
}

sum 10 200

echo $?
1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

function sum(){
let s=$1+$2

# 使用该写法可不受 return 的限制
echo $s
}

result=`sum 100 200`

echo $result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/bin/bash

if [ $# -ne 1 ];then
echo "参数错误"
exit 3
fi

# 任何一个大于 1 的数字,它的阶乘都等于 n * (n-1)

function jc(){
n=$1
if [ $n -le 1 ];then
# 函数的返回值
echo 1

# 返回函数的执行状态
return 0
elif [ $n -gt 1 ];then
let pre_n=n-1
temp=`jc $pre_n`
let result=n*temp

echo $result

return 0
fi
}

jc $1

Shell 工具

cut

cut 的基本语法

1
cut [选项参数] 文件名
参数 作用
-f 指定列数
-d 指定分隔符号

cut 的示例

1
2
3
4
5
6
7
8
9
10
# 取第一至第五列
[root@ahost Desktop]# cut -d":" -f1-5 /etc/passwd
root:x:0:0:root
bin:x:1:1:bin
daemon:x:2:2:daemon
adm:x:3:4:adm
lp:x:4:7:lp
sync:x:5:0:sync
shutdown:x:6:0:shutdown
...
1
2
3
4
5
6
7
8
9
10
# 取第一和第七列
[root@ahost Desktop]# cut -d":" -f1,7 /etc/passwd
root:/bin/bash
bin:/sbin/nologin
daemon:/sbin/nologin
adm:/sbin/nologin
lp:/sbin/nologin
sync:/bin/sync
shutdown:/sbin/shutdown
...
1
2
3
4
5
# 输出可以登录的用户的用户名
[root@ahost Desktop]# grep "bin/bash$" /etc/passwd | cut -d: -f1
root
java
hiyori
1
2
3
4
5
# 取环境变量 $PATH 的第一段配置
[root@ahost Desktop]# echo $PATH
/usr/local/soft/java/jdk1.8.0_40/bin:/usr/local/soft/java/jdk1.8.0_40/jre/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
[root@ahost Desktop]# echo $PATH | cut -d: -f1
/usr/local/soft/java/jdk1.8.0_40/bin

sed

Linux sed 命令是利用脚本来处理文本文件。
sed 可依照脚本的指令来处理、编辑文本文件。
Sed 主要用来自动编辑一个或多个文件、简化对文件的反复操作、编写转换程序等。

sed 的基本语法

1
sed [选项] '命令' 文件名
选项 作用
-e 同时指定多组命令
-i 将修改的内容直接作用到文件中
命令 作用
a 在 [n]a 行后新增内容
d 删除
s 查找替换

sed 的示例

1
2
3
4
5
6
7
8
# 在第二行(第一行后)新增指定内容
[root@ahost Desktop]# sed -i '1a Спасибо' sed.txt
[root@ahost Desktop]# cat sed.txt
Откыть центр уведомлрений
Спасибо
Очистить уведомления
Набросок на фрагменте экрана
[root@ahost Desktop]#
1
2
3
4
5
# 删除第四行
[root@ahost Desktop]# sed '4d' sed.txt
Откыть центр уведомлрений
Спасибо
Очистить уведомления
1
2
3
4
5
# 查找指定字符,执行相应的操作
[root@ahost Desktop]# sed '/Очистить уведомления/d' sed.txt
Откыть центр уведомлрений
Спасибо
Набросок на фрагменте экрана
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
[root@ahost Desktop]# cat sed.txt 
Откыть центр уведомлрений
Спасибо
Очистить уведомления
Набросок на фрагменте экрана
Папа Мама
Мама Папа
Папа Папа
Мама Мама

[root@ahost Desktop]# sed 's/Папа/Мама/' sed.txt
Откыть центр уведомлрений
Спасибо
Очистить уведомления
Набросок на фрагменте экрана
Мама Мама
Мама Мама
Мама Папа
Мама Мама

# 通常只替换匹配到的第一个单词,而 g 则代表全局替换
[root@ahost Desktop]# sed 's/Папа/Мама/g' sed.txt
Откыть центр уведомлрений
Спасибо
Очистить уведомления
Набросок на фрагменте экрана
Мама Мама
Мама Мама
Мама Мама
Мама Мама

1
2
3
4
5
6
7
8
9
# 删除第五行并查找替换指定字符
[root@ahost Desktop]# sed -e '5d' -e 's/Папа/Мама/' sed.txt
Откыть центр уведомлрений
Спасибо
Очистить уведомления
Набросок на фрагменте экрана
Мама Мама
Мама Папа
Мама Мама

awk

AWK 是一种处理文本文件的语言,是一个强大的文本分析工具。
之所以叫 AWK 是因为其取了三位创始人 Alfred Aho,Peter Weinberger, 和 Brian Kernighan 的 Family Name 的首字符。

awk 的基本语法

1
awk [选项] '匹配模式1{命令1} 匹配模式2{命令2} ...' 文件名
选项 用作
-F 指定分隔符
-v 定义变量

awk 的内置变量

名称 含义
FILENAME 文件名
NR 已读的记录数
NF 浏览记录的域的个数(切割后,列的个数)

awk 的示例

1
2
3
4
5
6
7
8
9
# 输出第一列和第二列的数据
[root@ahost Desktop]# awk -F: '{print $1 "," $2}' passwd
root,x
bin,x
daemon,x
adm,x
lp,x
sync,x
shutdown,x
1
2
3
# 查找指定用户,并输出用户名和该用户所使用的shell
[root@ahost Desktop]# awk -F: '/^hiyori/ {print $1 ", " $7}' passwd
hiyori, /bin/bash
1
2
3
4
5
6
7
8
9
10
11
12
# 使用 BEGIN{} 和 END{} 定义首尾信息
[root@ahost Desktop]# awk -F: 'BEGIN{print "username | shell"} {print $1" | " $7} END{print "End"}' passwd
username | shell
root | /bin/bash
bin | /sbin/nologin
daemon | /sbin/nologin
adm | /sbin/nologin
lp | /sbin/nologin
sync | /bin/sync
shutdown | /sbin/shutdown
...
End

sort

Linux sort 命令用于将文本文件内容加以排序。
sort 可针对文本文件的内容,以行为单位来排序。

Linux sort 命令

sort 的基本语法

1
sort [选项] 文件名

sort 的示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# sort 命令将以默认的方式将文本文件的第一列以 ASCII 码的次序排列,并将结果输出到标准输出。
[root@ahost Desktop]# sort sed.txt
Мама Мама
Мама Папа
Набросок на фрагменте экрана
Откыть центр уведомлрений
Очистить уведомления
Папа Мама
Папа Папа
Спасибо

[root@ahost Desktop]# sort sed.txt -k 2
Спасибо
Папа Мама
Мама Мама
Набросок на фрагменте экрана
Мама Папа
Папа Папа
Очистить уведомления
Откыть центр уведомлрений

[root@ahost Desktop]# cat sed.txt
Откыть центр уведомлрений
Спасибо
Очистить уведомления
Набросок на фрагменте экрана
Папа Мама
Мама Папа
Папа Папа
Мама Мама

拓展

Shell 输入/输出重定向
Shell 文件包含