一、什么是Shell
Shell 是操作系统中的一个 命令行解释器,主要功能是接收用户命令,然后将这些命令传递给操作系统内核去执行。 Shell 是用户与操作系统内核之间的接口,它允许用户通过命令行或脚本来与操作系统进行交互。同时,Shell 也是一种脚本语言,允许用户编写一系列命令脚本(Shell脚本)以实现自动化任务处理。
我们可以查看 /etc/shells
文件查看 Linux 提供的 Shell 解释器有哪些。
cat /etc/shells
然后,我们可以执行 echo $SHELL
命令查看默认使用的是哪个 Shell 解释器。
echo $SHELL
二、一个简易的Shell脚本
这里,我们使用 vim 新建一个 Shell 脚本。然后,我们在 hello.sh 脚本文件中编写脚本。
#!/bin/bash
echo "Hello world!"
编写完成之后,我们保存退出该脚本文件。然后,我们可以在终端中通过 sh
命令执行 Shell 脚本。
sh hello.sh
我们也可以直接运行 hello.sh 脚本文件。
./hello.sh
当我们直接运行脚本文件时会发现显示权限,这是因为,hello.sh 脚本文件默认没有执行权限。此时,我们可以通过 chmod
命令修改文件权限。
三、变量
在 Shell 编程中,变量是用于存储数据值的名称。我们可以使用 变量名=变量值
的方式 定义变量,然后通过 $变量名
的方式 获取变量的值。在定义变量时,变量名和等号之间不能有空格。如果变量后面不想使用的话,可以使用 unset 变量名
的方式撤销变量。如果我们要 定义只读变量,可以使用 readonly 变量名=变量值
的方式。只读变量不能使用 unset 撤销。如果我们想要变量 提升为全局变量 供给其它 Shell 程序使用,可以使用 export 变量名
的方式。
同时,变量名的命名须遵循如下规则:
- 只包含字母、数字和下划线:变量名可以包含字母(大小写敏感)、数字和下划线,不能包含其他特殊字符。
- 不能以数字开头:变量名不能以数字开头,但可以包含数字。
- 避免使用 Shell 关键字:不要使用Shell的关键字(例如 if、then、else、fi、for、while 等)作为变量名,以免引起混淆。
- 避免使用空格:变量名中不应该包含空格,因为空格通常用于分隔命令和参数。
在 Shell 中,变量值默认都是字符串,如果字符串直接包含空格,则要使用单引号或者双引号括起来。
我们在使用 Shell 时,Shell 中有几个特殊字符用来处理参数:。
$n
:在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为$n
,n 代表一个数字,0 是 执行的文件名,1 为执行脚本的第一个参数,是传入的第一个参数。2 为执行脚本的第二个参数。如果 n 大于 9,需要使用大括号括起来。$#
:传递到脚本的参数个数。$*
:以一个单字符串显示所有向脚本传递的参数。$@
:与$*
相同,但是使用时加引号,并在引号中返回每个参数。$?
:显示最后命令的退出状态。0 表示没有错误,其它任何值表明有错误。$$
:脚本运行的当前进程 ID 号。$-
:显示 Shell 使用的当前选项,与 set 命令功能相同。
#!/bin/bashecho '---------- $n ----------'
echo $0
echo $1
echo $2
echo ${10}echo '---------- $# ----------'
echo $#echo '---------- $* ----------'
echo $*echo '---------- $@ ----------'
echo $@echo '---------- $? ----------'
echo $?echo '---------- $$ ----------'
echo $$echo '---------- $- ----------'
echo $-
四、运算符
在 Shell 中,我们不能直接将运算式赋值给变量,这是因为变量值默认都是字符串。此时我们可以使用 $((运算式))
或 $[运算式]
的方式赋值给变量。
五、条件判断
我们可以使用 test 条件表达式
或 [ 条件表达式 ]
进行条件判断。当条件表达式为真时输出 0,否则输出 1。我们还可以判断条件表达式是否为空,其中非空为真,空为假。
常用的条件判断如下:
- 两个整数之间的比较:
-eq
:等于(equal)。-ne
:不等于(not equal)。-lt
:小于(less than)。-le
:小于等于(less equal)。gt
:大于(greater than)。-ge
:大于等于(greater equal)。
- 按文件权限进行判断:
-r
:有读的权限(read)。-w
:有写的权限(write)。-x
:有执行的权限(execute)。
- 按文件类型进行判断:
-e
:文件存在(existence)。-f
:文件存在并且是一个常规文件(file)。-d
:文件存在并且是一个目录(directory)。
我们还可以进行多条件判断,其中 &&
表示 前一条命令执行成功时,才执行后一条命令,||
表示 上一个命令执行失败后,才执行下一条命令。
六、流程控制
6.1、分支结构
6.1.1、if分支结构
我们可以使用 if 语句执行单分支结构。
if [ 条件判断式 ]; then程序
fi
或
if [ 条件判断式 ]
then程序
fi
如果我们要执行多分支逻辑,可以通过以下方式:
if [ 条件判断式 ]
then程序
elif [ 条件判断式 ]
then程序
else程序
fi
#!/bin/bashif [ $1 -eq 10 ]; thenecho "num == 10"
elif [ $1 -lt 10 ]
thenecho "num < 10"
elseecho "num > 10"
fi
6.1.2、case分支结构
我们可以使用 case 分支结构判断变量的值是否等于某个值。
case $变量名 in
"值1")如果变量的值等于值1,则执行程序1
;;
"值2")如果变量的值等于值2,则执行程序2
;;...省略其它分支...
*)如果变量的值都不是以上的值,则执行此层序
;;
esac
#!/bin/bashcase $1 in"1")echo "the first";;"2")echo "the second";;"3")echo "the third";;*) echo "loser";;
esac
我们还可以使用 |
合并多个条件。
#!/bin/bashcase $1 in"0")echo "the number is 0";;"1" | "3" | "5" | "7" | "9")echo "this is an odd number less than 10";;"2" | "4" | "6" | "8")echo "this is an even number less than 10";;*)echo "this is other number";;
esac
6.2、循环结构
6.2.1、for循环结构
for 循环的语法格式如下:
for ((初始值;循环控制;迭代控制))
do程序
done
#!/bin/bashsum=0
for ((i = 0; i <= 10; i++)); dosum=$[$sum+$i]
doneecho $sum
然后我们在终端中如下如下命令执行 Shell 脚本:
bash template.sh
我们还可以使用如下语法遍历值:
for 变量 in 值1 值2 值3 ...
do程序
done
#!/bin/bashfor name in sakura mikoto shana
doecho "$name is a gril"
done
$*
和 $@
都表示传递给函数或脚本的所有参数,不被双引号包含时都以 $1 $2 ... $n
的格式输出所有参数。但是如果用双引号括起来,"$*"
表示一个变量,"$@"
分为多个变量。
#!/bin/bashecho '---------- $* ----------'
for name in $*
doecho "$name is gril"
doneecho '---------- $@ ----------'
for name in $@
doecho "$name is gril"
doneecho '---------- "$*" ----------'
for name in "$*"
doecho "$name is gril"
doneecho '---------- "$@" ----------'
for name in "$@"
doecho "$name is gril"
done
6.2.2、while循环结构
while 循环结构的语法如下:
while [ 条件表达式 ]
do程序
done
#!/bin/bashi=1
sum=0while [ $i -le 100 ]
dosum=$[$sum+$i]i=$[$i+1]
doneecho $sum
然后我们在终端中如下如下命令执行 Shell 脚本:
bash template.sh
七、控制台输入
我们可以使用 read
命令读取控制台输入
read [选项] 参数
read
命令可选的选项如下:
\p
:指定读取值时的提示词。\t
:指定读取值等待的时间(单位为秒),如果 -t 不加表示一直等待。
#!/bin/bashread -t 7 -p "Pleases enter your name within 7 seconds:" nameecho "Hello $name"
八、函数
在 Shell 中,我们可以自定义函数,它的格式如下:
function 函数名()
{函数体;return 函数返回值
}
其中,function 表示是这是一个函数,可以省略。
Shell 脚本是逐行运行的,因此在调用函数之前,必须先声明函数。Shell 脚本中,函数的返回值只能通过 $?
系统便两个获得,可以显示使用 return 函数返回值
(函数的返回值只能是 0 到 255 之间的数值,其中 0 表示运行成功,其它值都表示错误)的方式返回。如果不显示的返回,则将以最后一条命令运行结果作为函数返回值。
#!/bin/bashfunction sum()
{s=$[$1+$2]echo $s
}read -p "Please enter the first number:" n1
read -p "Please enter the second number:" n2sum $n1 $n2
九、Shell工具
9.1、cut工具
cut
工具用来在文件中剪切数据,cut
命令从文件中每一行剪切字节、字符和字段并将这些字节、字符和字段输出。它的基本用法如下:
cut [选项] 文件名
其中,它的选项可选值如下:
-f 列号
:提取第几列。-d 分隔符
:分隔符,按照指定分隔符分割列,默认是制表符\t
。-c n
:按字符进行切割,n 表示取第几列。
9.2、awk工具
awk
是一个强大的文本分析工具,它把问嗯逐行的读入,以空格为默认的分隔符将每行切片,切开的部分在进行分析处理。
awk [选项] '/匹配模式/{匹配时所要执行的一系列命令}' 文件名
其中,选项的可选值如下:
\F
:指定输入文件的分隔符。\v
:赋值一个用户定义变量。
匹配模式 如果省略,则 awk
将对所有行进行操作。匹配时所要执行的一系列命令 如果省略,则默认动作是打印整行。
我们还可以使用 BEGIN{}
和 END{}
在匹配时所要执行的一系列命令添加前置操作和后置操作。
awk 还内置了一些变量,例如:
FILENAME
:文件名。NR
:以读的记录数(行号)。NF
:浏览记录的域的个数(切割后,列的个数)。
awk -F : '{print "filename: " FILENAME ", row:" NR ", col:" NF}' /etc/passwd