1. shell简介
shell可直译为“贝壳”,贝壳是动物作为外在保护的一种工具。可以理解为:Linux中的 shell就是 Linux内核的一个外层保护工具,并负责完成用户与内核之间的交互。命令是用户向系统内核发出控制请求,与交互的文本流。而 shell是一个命令行解释器,将用户命令解析为操作系统所能理解的指令,实现用户与操作系统的交互。当需要重复执行若干命令,可以将这些命令集合起来,加入一定的控制语句,编辑成为 shell脚本文件,交给 shell批量执行。

最初的 UNIX shell经过多年的发展,由不同的机构、针对不同的目录,开发出许多不同类型的 shell程序,目前流行的 shell主要有以下几种:
- Bourne Shell(sh):由 AT&T的 Steve Bourne开发,是第一个流行的 shell,是 UNIX上的标准 shell。不过 sh的作业控制功能薄弱,且不支持别名与历史记录等功能
- C Shell(csh):sh之后另一个广为流传的 shell,由柏克莱大学的 Bill Joy设计,语法有点类似 C语言,其内部命令有52个,较为庞大。但目前使用的不多
- Korn Shell(ksh):由AT&T 的David Korn开发,语法与 sh相同,同时具备 csh的易用特点。许多安装脚本都使用 ksh,有42条内部命令,但与 bash 相比有一定的限制性
- Bourne Again Shell(bash):由 GNU组织开发,保持了对 sh的兼容性,是各种Linux发行版默认配置的shell。能够提供环境变量以配置用户 shell环境,支持历史记录,内置算数功能,支持通配符表达式,将常用命令内置简化
2. shell命令格式
2.1 shell命令提示符
shell提示符标识了命令行的开始。用户在提示符后面输入一条命令并按 Enter键,完成向系统提交命令。通常 shell命令提示符采用以下格式:
username@hostname:direction$
用户名 主机名 目录名
- username:用户名,显示当前登录用户的账户名(执行命令 whoami)
- hostname:主机名,显示登录的主机名(执行命令 hostname)
- direction:目录名,显示当前所处的路径,根目录下显示为“/”,主目录下显示为“~“(执行命令 pwd)
2.2 shell命令格式
通常一条 shell命令包含三个要素:命令名称、选项、参数。命令名称是必须的,选项和参数都可选项。格式如下:
$ Command [-Options] Argument1 Argument2...
指令 选项 参数1 参数2 ...
- $:shell提示符,若为超级用户,提示符为“#”,其他用户的提示符均为“$”
- Command:命令名称,shell命令或程序,严格区分大小写
- Options:命令选项,用于改变命令执行类型,由“-”引导,可同时带多个选项
- Argument:命令参数,指出命令作用的对象或目标,允许带多个参数
一条命令的三要数之间用空格隔开;若将多个命令在一行书写,用分号(;)将各命令隔开;如果一条命令不能在一行写完,在行尾使用反斜杠(\)表明该条命令未结束。
2.3 shell命令初体验
使用shell命令,关闭或重启系统
sudo shutdown -h now #系统立即关机
sudo shutdown -r now #系统立即重启
sudo reboot now #系统立即重启
sudo shutdown -h +45 "That is all!" #系统45分钟后关机
sudo shutdown -r +60 #系统60分钟后重启
3. shell中的特殊字符
3.1 shell中的通配符当需要用命令处理一组文件,例如 file.txt、file2.txt、file3.txt…,用户不必一一输入文件名,可使用 shell通配符。shell命令的通配符含义如下表

3.2 shell中的管道
管道可以把一系列命令链接起来,意味着第一个命令的输出将作为第二个命令的输入,通过管道传递给第二个命令,第二个命令的输出又将作为第三个命令的输入,以此类推。就像通过使用“|”符连成一个管道。
ls /use/bin | wc -w
1249
以上操作中,借助管道“|”,将 ls的输出直接作为 wc命令的输入。使用管道可以巧妙的将一些命令联合使用,得到单个命令所无法实现的效果。例如使用以上的命令组合,得到的是/usr/bin目录下文件的个数。
3.3 输入输出重定向
输入输出重定向是改变 shell命令或程序默认的标准输入输出目标,重新定向到新的目标。linux中默认的标准输入定义为键盘,标准输出定义为终端窗口。用户可以为当前操作改变输入或输出,迫使某个特定命令的输入或输出来源为外部文件

cat命令功能为在标准输出上显示文件。下面通过一个实例,可以更好地理解重定向的功能:
an@ubuntu:~/di$ cat #使用标准输入/出设备
hello world! #用户使用标准输入设备键盘,键入字符串,并按Enter键
hello world! #系统在标准输出显示器上,显示用户刚刚输入的字符串
an@ubuntu:~/di$ cat > file1.txt #输出重定向,将输出定向到文件file1.txt
hello world! #用户使用标准输入设备键盘,键入字符串,并按Enter键
#用户输入的字符串被保存在file1.txt文件中
an@ubuntu:~/di$ cat < file1.txt #输入重定向,将cat的输入指定为file1.txt
hello world! #系统在标准输出显示器上,显示cat命令从文件中读出的字符串
3.4 命令置换
命令替换是将一个命令的输出作为另一个命令的参数。命令格式如下所示:
command1 `command2`
其中,命令 command2的输出将作为命令 command1的参数。需要注意,命令置换的单引号为ESC键下方的“`”键
linux@ubuntu:~$ ls `pwd`
Desktop Examples linux andyxi
pwd命令用于显示当前目录的绝对路径。在上面的命令行中,使用命令置换符,将 pwd的运行结果作为 ls命令的参数。最终,命令执行结果是显示当前目录的文件内容。
1. shell脚本基础知识
shell脚本是一个文件,里面存放的是特定格式的指令,系统可以使用脚本解析器翻译或解析指令并执行(无需编译),shell脚本的本质是shell命令的有序集合shell脚本编程的基本过程分为三步:
⏩ 建立shell文件:包含任意多行操作系统命令或shell命令的文本文件
vi test.sh
⏩ 赋予shell文件执行权限:用chmod命令修改权限
chmod 740 test.sh
⏩ 执行shell文件:直接在命令行上调用shell程序
./test.sh
2. shell变量
shell允许用户建立变量存储数据,但不支持数据类型(整型、字符、浮点型), 任何赋给变量的值都被解释为一串字符。
定义shell变量名时,首个字符必须为字母,不能以数字开头,中间不能有空格,可以使用下划线,不能使用中横线及标点符号等。shell变量分为系统变量、环境变量和用户变量三种:
⏩ 用户变量:用户自定义变量,通常使用全大写定义变量名,方便识别;在变量前加 $ 调用变量;从右向左赋值;unset命令可删除变量的赋值
COUNT=1 #通常使用全大写定义变量名,方便识别
echo $HOME #在变量前加 $ 调用变量
# Linux Shell/bash从右向左赋值
Y=y
X=$Y
echo $X
y
#使用unset命令删除变量的赋值
Z=hello
echo $Z
hello
unset Z
echo $Z
⏩ 系统变量:用于对参数判断和命令返回值判断时使用
$0 #当前脚本的名称
$n #传递给脚本或函数的第n个参数,n=1,2,…9
$# #传递给脚本或函数的参数个数
$* #传递给脚本或函数的所有参数:“$1,$2,……$9” 整体传递
$@ #传递给脚本或函数的所有参数:“$1”,“$2”,……“$9” 分开传递
$? #命令或程序执行完后的状态,返回0表示执行成功
$$ #当前脚本程序的PID号
⏩ 环境变量:在程序运行时需要设置
PATH #shell搜索路径,以冒号为分割
HOME #/etc/passwd文件中列出的用户主目录
SHELL #当前Shell类型
USER #当前用户名
ID #当前用户id信息
PWD #当前所在路径
TERM #当前终端类型
HOSTNAME #当前主机名;
PS1 #定义主机命令提示符
HISTSIZE #历史命令大小,可通过HISTTIMEFORMAT变量设置命令执行时间
RANDOM #随机生成一个0至32767的整数
HOSTNAME #主机名
3. shell功能语句
shell脚本程序由单条或多条shell语句构成。shell语句包括三类:说明性语句、功能性语句和结构性语句
⏩ 说明性语句:即注释行,以 # 号开始到该行结束,不被解释执行
#! /bin/sh
# 以上是告诉OS用哪种类型的shell来解释执行该程序
⏩ 功能性语句:任意的shell命令、用户程序或其它shell程序。以read命令和expr命令为例
read命令:read从标准输入读入一行, 并赋值给后面的变量。若标准输入无数据, 则程序在此停留等侯, 直到数据到来或被终止运行
read var #把读入的数据全部赋给var
read var1 var2 var3 #把读入行中的第一个词赋给var1,第二个赋给var2,其余所有赋给var3
expr命令:用于简单的整数运算,包括加(+)、减(-)、乘(*)、整除(/)和求模(%)等操作
expr 12 + 5 \* 3 #反斜线\去掉*号的元字符含义
27
expr 3 - 8 / 2
-1
#####
num=9
sum=`expr $num \* 6` #反撇号`引用命令的运行结果
echo $sum
54
⏩ 结构性语句:根据程序的运行状态、输入数据、变量的取值、控制信号以及运行时间等因素来控制程序的运行流程。主要包括条件测试语句、多路分支语句、循环语句、循环控制语句和后台执行语句等
测试语句:test语句可测试字符串、整数和文件属性
test "$answer" = "yes" #变量answer的值是否为字符串yes
test $num –eq 18 #变量num的值是否为整数18
test -d tmp #测试tmp是否为一个目录名
##### 字符串测试 #####
s1 = s2 #测试两个字符串的内容是否完全一样
s1 != s2 #测试两个字符串的内容是否有差异
-z s1 #测试s1字符串的长度是否为0
-n s1 #测试s1字符串的长度是否不为0
##### 整数测试 #####
a -eq b #测试a与b是否相等
a -ne b #测试a与b是否不相等
a -gt b #测试a是否大于b
a -ge b #测试a是否大于等于b
a -lt b #测试a是否小于b
a -le b #测试a是否小于等于b
##### 文件测试 #####
-d name #测试name是否为一个目录
-e name #测试一个文件是否存在
-f name #测试name是否为普通文件
-L name #测试name是否为符号链接
-r name #测试name文件是否存在且为可读
-w name #测试name文件是否存在且为可写
-x name #测试name文件是否存在且为可执行
-s name #测试name文件是否存在且其长度不为0
f1 -nt f2 #测试文件f1是否比文件f2更新
f1 -ot f2 #测试文件f1是否比文件f2更旧
条件语句
if [condition1]; then
...
elif [condition2]; then
...
else
...
fi
多路分支语句
case $variable in
"case1")
......
;;
"case2")
......
;;
"case3")
......
;;
*)
......
;;
esac
循环语句
for var in con1 con2 con3 ...
do
......
done
while [condition]
do
......
done
循环控制语句
break #终止执行所有循环
continue #终止该次循环,进行下次循环
4. shell函数
把一个功能封装起来,使用时直接调用函数名,模块化,代码可读性强,扩展性方便。shell中有两种定义函数的语法格式:
# 若写了function,可以省略函数名后的括号
function fname {
......
}
# 不写function时,函数名后需要加括号
fname() {
......
}
和其他编程语言不同的是,shell函数在定义时不能指明参数,但在调用时却可以传递参数,并且给它传递什么参数它就接收什么参数。当然调用函数时也可以不传递参数。函数调用方法如下:
# 不传递参数时,直接给出函数名即可
fname
# 如果要传递参数,多个参数之间以空格分开
fname param1 param2 param3
如下函数调用实例1:运行脚本后,输出www.baidu.com
#!/bin/bash
#定义函数
function url {
echo "www.baidu.com"
}
#调用函数
url
如下函数调用实例2:运行脚本后,输出传参值之和
#!/bin/bash
#定义函数:获取参数的和
function get_sum() {
local sum=0
for n in $@
do
((sum+=n))
done
return $sum
}
#调用函数并传递参数
get_sum 10 2 5 7 9 12 50
echo $?
转载请注明:XAMPP中文组官网 » 一文读懂 Shell 脚本编程知识