精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>电脑技术>>● FreeBSD>>《FreeBSD使用大全》第二版>>3.3.2 shell的高级功能

主题:3.3.2 shell的高级功能
发信人: sungang(笨刚)
整理人: sungang(2003-09-16 11:39:43), 站内信件
3.3.2 shell的高级功能

由于shell是Unix下用户最经常使用的界面,因此熟练掌握必然带来更高的工作效率。事实上,仍然有很多种技巧,能帮助用户更方便的使用shell。

1) 命令行使用技巧
一个重要的增强功能是shell提供的命令行编辑功能,这包括能够使用上次执行过的指令(命令回溯),对已经输入的部分进行编辑等等。

注意:shell的这些增强功能是在最新版本(4.2之后)的系统中才加以添加的,因此不再需要额外安装tcsh或bash。新版的FreeBSD使用tcsh作为基本的csh,而sh的功能也得到了增强。如果是老版本的系统,则需要安装tcsh作为shell,或者安装bash,来获得这些增强功能。

然而,最新的sh缺省情况下并没有打开这个功能,因此必须首先打开这个功能,当打开这个功能之后,就能使用方向键来回溯执行过的命令,并进行修改。

$ set -o emacs 

$ set -o vi    

按照习惯的不同,可以选择vi风格的编辑方式或emacs风格的方式,而vi风格还能支持vi的键盘指令,即在按下Esc键之后,使用h、j、k、l四个键来移动光标和回溯命令,它的好处是不使用基本键盘之外的控制键,因而可以适用于任何终端设备,并且进行编辑时手不需离开基本键盘,熟练操作之后最为快捷。

最新版本的csh,即tcsh,缺省就支持命令回溯,但也能使用不同的命令切换编辑风格:

% bind emacs

% bind vi

另一个重要的功能是可以为常用的命令设置别名,简化用户输入,例如:

$ alias ec=“echo This is a alias”

$ ec

This is a alias

csh用于方便用户操作的另一项能力是自动补全命令或文件名的功能,因为FreeBSD下的文件名可能很长,将它们全部输入比较麻烦。事实上可以输入部分名字,然后按Tab键(在vi风格下是连续两次按Esc键),shell将自动补全文件名的剩余部分。如果已经输入的这部分名字不能确定具体的命令或文件,那么shell只将能确定的部分补上,然后响铃通知使用者继续输入以明确具体的文件。

事实上即使在基本的sh或csh下,也可以使用 “*” 等特殊字符,用模式匹配的方式来简化输入。

$ cd /usr/loca*

$ pwd

/usr/local

Unix中的多数程序都具备模式匹配的处理能力,而shell的模式匹配功能最为常用。shell可以使用这些特殊模式来配置多个文件,达到简化操作的目的。如果要熟练掌握Unix,必须掌握模式匹配。

2) 控制功能
Unix的shell不仅仅简单的接受输入指令并执行,它更强大的能力是能够根据条件解释执行输入指令。当然,sh和csh对于输入的解释语法有所不同,由于在系统中sh最为基本,以下以sh为例,简单介绍shell的控制功能。

最重要的功能之一是根据条件来判断是否需要完成某项工作。最简单的情况下,如果某个程序存在并可以执行,则执行执行这个程序,这种用法在启动脚本中十分常见。这需要使用逻辑“与”判断:

$ [ -x /usr/bin/echo ] && /usr/bin/echo “the program echo is running!”

the program echo is running!

与此相反的方式是,当条件不成立的时候执行程序,这需要逻辑“或”判断:

$ [ -f /tmp/somefiles ] || echo “somefiles is missing!”

somefiles is missing!

当然,无论哪一种逻辑判断形式,关键点是逻辑判断本身的语法。一般来讲,可以根据文件本身的属性进行判断,如上面例子中判断文件”-f”是否存在,”-x”判断文件是否是执行程序,还可以判断是否为目录”-d”,等等。此外,还可以根据字符串来进行判断,判断两个字符串是否相同、甚至比较大小,以及进行数学判断等等,下面将在介绍其他控制方式时给出一些例子。

更详细的判断条件,可以man test。事实上,判断语句中的括号[本身就是一个程序,就是test,这个程序根据后面的条件返回一定的结果。因此,完全可以直接根据一个程序的返回结果进行判断。

使用逻辑与和逻辑或进行逻辑判断,是逻辑判断的一种缩略形式,它的好处是能将几个命令放在一行中。更为标准的方法当然还是使用if判断语句。

$ if [ -d /home/user ] ; then echo “user directory is exist!” fi

user directory is exist!

此时由于有控制部分,将所有语句都写在一行上显然不是好主意,sh允许将这样一个语句分开完成的机制。

$ if [ ! -d /home/user1 ] 

> then 

>   echo “user1 directory is not exist!” 

> fi

注意,”>“为shell的提示符号而不是语句本身,当语句还没有完成的时候,sh使用提示符”>“,而不是标准的”$”,这个提示符是由环境变量PS2决定的。这个语句中增加了逻辑非的判断。

除了根据文件的属性进行判断之后,更多的情况下需要判断字符串是否相同:

$ if [ “X$TERM” = “Xansi” ] 

> then 

>   echo “ansi terminal is not supported in FreeBSD!” 

> elif [“X$TERM” > “Xvt0” && “X$TERM” < “Xvt9” ]

> then 

>   echo “vtXXX serial terminal is ok!”

> else

>   echo “terminal maybe ok!”

> fi

上面例子中使用了if,elif,else等多重判断形式,甚至还判断了字符串的大小,判断$TERM是否是vt系列的终端。

这里应用了一个小技巧,就是不直接判断$TERM本身,而是添加上一个额外的字符’X’,这是因为$TERM可能为空变量,这种情况下判断语句本身就会出现语法错误,添加上一个额外的字符就可以避免这个问题。

当然,如果是判断结果可能是多个字符串之一,那么就需要使用case语句:

$ case “$gateway_enable”  in

> [Yy][Ee][Ss])

>            echo “$gateway is yes”

>            ;;

> *)

>            ;;

>  esac  

这种形式在系统启动脚本中也非常常见,注意,这里使用了中括号来忽略变量中的大小写,事实上这是一种模式匹配的方法,方括号内的任一字符都匹配对应字符。

了解了逻辑判断语句之后,循环语句也非常自然了,因为循环原则上也是一个逻辑判断,加上循环的主体而已。

$ COUNT=1; export COUNT

$ while [ $COUNT -lt 10 ]

> do

>   echo “count is $COUNT”

>   COUNT=`expr $COUNT + 1`

> done

这个例子中,我们首先设置了一个环境变量,然后在这个变量小于10的时候执行循环。当然,循环内部使用了反引号,调用外部程序expr,将该变量自动加一。这就是shell的一个弱点,处理数学计算的时候必须使用外部程序,shell在处理字符串的时候相对简单,有很多内部功能可以利用,比如直接将两个变量放在一起,就能完成字符串的合并任务。

如果循环次数比较少,也可以使用这种字符串判断的方法:

$ while [ “X$loopflag” < “X1111111111” ]

> do

>   echo “flag is $loopflag”

>   loopflag=${loopflag}1

> done

这里每个循环向循环变量后面附加上一个字符,直到循环变量大于某个值为止。

其实,另一种循环方式更为直接,也更方便,就是使用for语句。

$ for COUNT in 0 1 2 3 4 5 6 7 8 9

> do

>   echo “count is $COUNT”

> done

通过枚举的方式把所有循环可能性列出,更为简单、可靠,而不需要任何其他的外部程序。 这种方法的缺点是如果循环的数量较多就比较麻烦了,如果是这种情况,最好是使用多级循环的方式来解决。

其实for循环后面的枚举完全可以和sh的其他功能组合起来,充分发挥功能。

$ for cfile in *c

> do

>   echo “in current directory, there is $cfile”

> done

上例可以对当前目录下的所有c文件进行处理,这就是sh自动将*c这个带有模式的输入自动展开为所有匹配的文件名的列表。

$ for cfile in `ls`

> do

>   echo “in current directory, there is $cfile”

> done

这是另一种形式,使用反引号,让sh启动ls命令,而ls命令的结果作为for的参数。

[关闭][返回]