众所周知,Linux 的精髓就在于其强大的命令行,命令行的作用就是与系统提供的命令或内核提供的系统调用进行交互,而 shell 就承担了这一任务。
Linux 下常见的 shell 有 ksh,csh,sh,tcsh,bash 等,可在 /etc/shells 文件查看,这里不表。本文以 bash 为例。
shell 的工作原理为:
接下来讲 shell 的语法
shell 中变量分为本地变量和环境变量。可以通过 export 命令将一个本地变量更新为环境变量。unset 可以删除一个变量。
本地变量不用定义,第一次使用时直接拿来用即可。例如 val=10
。之后需要取得该变量的值时,前面加一个 $
符号即可,例如 echo $val
。
环境变量是形如 name=val
形式的字符串,可以通过 printenv
命令查看所有的环境变量。
shell 允许一个命令的输出成为另一个命令的一部分,即命令代换。例如 echo `date`
,shell 先执行一对反引号中的命令,并用其输出替换命令本身,再执行 echo
命令。反引号可以用 $()
替换。
shell 中的单引号和双引号都用来表示字符串的定界符,所不同的是单引号中所有字符都表示它本身的意义,包括 \
和回车符号。而双引号中
$
加变量名仍然可以取变量的值\
表示转义字符条件测试有两种命令,test
和 [
,例如:
test $a -gt 10 && echo 'gt 10'
[ $a -gt 10 ] && echo 'gt'
可以看出,[
命令需要 ]
来配对,并且他们与里面的语句之间必须要有一个空格。
gt
是比较操作,意为大于(Greater Than),其他比较操作还有小于(Less Than,lt),等于(EQual,eq),大于等于(Greater or Equal,ge),小于等于(Less or Equal,le),不等于(Not Equal,ne)等。
if 表示判断条件是否为真,其语法形式如下:
a=10
if [ $a -gt 10 ]
then
echo 'gt'
elif [ $a -lt 10 ]
then
echo 'lt'
else
echo 'eq'
fi
shell 中分支语句为 case/esac
,示例如下:
a=10
case $a in
1)
echo 'a is 1'
;;
10)
echo 'a is 10'
;;
100)
echo 'a is 100'
;;
*)
echo 'a is other'
;;
esac
当 a 为 1 或 10 或 100 时,就会跳转到对应的语句上执行,然后遇到两个分号时跳出。星号代表通配符,类似于 C语言中的 default
语句。
for 循环有两种形式,如下:
sum=0
for i in {1..100}
do
((sum=$sum+$i))
done
echo $sum
或者
sum=0
for ((i=0;i<=100;++i))
do
((sum=$sum+$i))
done
echo $sum
sum=0
i=0
while [ $i -le 100 ]
do
((sum=$sum+$i))
((i++))
done
echo $sum
shell中的特殊变量有
$0
:相当于 argv[0]$1…
:相当于 argv[1]…$@
:表示参数列表,即 $1,$2,…$#
:相当于 argc-1$?
:表示上一条命令的退出码$$
:表示当前 shell 的进程号位置参数可以通过 shift 命令左移,若 shift 后面不跟数字,则默认为 1
函数定义和 C语言差不多,只不过 shell 中函数没有参数和返回值。取而代之的是,参数继续用 $1
,$2
来使用,返回值用 return
或 echo
命令返回。下面是一个著名的 fork 炸弹::(){ :|:& };:
。
它可以分解成:
:()
{
:|:&
};
:
其中 : 是函数名,括号代表是一个函数,一对花括号代表函数的起始和结束,在函数体里面递归调用本身并将输出通过管道传递给另一个该函数,并放入后台执行。所以进程数会以2n增长,造成系统无响应,只能重启。解决方法是通过 ulimit 命令限制一个用户最多可以创建的进程数。
shell 脚本的调试方法为在解释器语句后面加上 -x
选项,在执行时会打印出执行的每一条语句。
【完】