linux_shell笔记(八)
来源:互联网 发布:全国小龙虾消费数据 编辑:程序博客网 时间:2024/04/30 23:52
<!--@page { margin: 2cm }P { margin-bottom: 0.21cm }-->
Bash 程序设计
控制结构:控制结构有if...then、for...in、while、until、case语句。与控制结构配合使用的还有break和continue语句也可用于调整shell脚本中的命令执行顺序。
if...then:
if test-command
then
command
fi
test内置命令:if测试test-command返回状态,并基于这个状态转移控制。if语句的结束由fi标记。
echo -n “word1:”
read word1
echo -n “word2:”
read word2
if test“$word1” = ”$word2”
then
echo “Match”
fi
echo “End ofprogram.”
上面echo利用'-n'选项来表示输出echo参数后不用换行。
在bash中test是一个内置命令,也就是它是shell的一部分。同时还有一个单独的工具test。通常某个命令的工具版本不存在,而内置命令版本可用时,使用后者。test测试语句中使用的'='两边的空白字符不可以省略。
test的操作符'-eq'比较两个整数,特殊变量$#表示命令行参数的个数。
if test $# -eq0
then
echo “Youmust supply at least one argument.”
exit1
fi
echo “Programrunning.”
可以利用'infotest'得到完整的test用法信息:
测试文件类型:'-bFILE' '-c FILE' '-d FILE' '-f FILE' '-h FILE' '-L FILE' '-pFILE' '-S FILE' ‘-t FD’
访问权限测试:'-gFILE' '-k FILE' '-r FILE' '-u FILE' '-w FILE' '-x FILE' '-OFILE'
'-G FILE'
文件特征比较:'-eFILE' '-s FILE' 'FILE1 -nt FILE2' 'FILE1 -ot FILE2'
'FILE1 -efFILE2'
字符串测试:'-zSTRING' '-n STRING' 'STRING' 'STRING1 = STRING2'
'STRING1 !=STRING2'
整数测试:'ARG1-eq ARG2' 'ARG1 -ne ARG2' 'ARG1 -lt ARG2' 'ARG1 -le ARG2'
'ARG1 -gtARG2' 'ARG1 -ge ARG2'
测试条件连接词:'!EXPR' 'EXPR1 -a EXPR2' 'EXPR1 -o EXPR2'(注意中间的空白符号)
[]与test同义可以把test的参数用方括号括起来,以代替在脚本中使用关键字test。括号两边必须有空白符
if [ $# -eq 0 ]
then
ehco “Usage: chkarg2 argument...” 1>&2
exit 1
fi
echo “Programrunning.”
exit 0
用法信息上面例子显示的信息称为用法信息,使用'1>&2'标记可把这个输出重定位到标准错误输出。在脚本正常运行后一般退出状态为0,如果退出状态非0表示遇到一个错误。
if...then...else
if test-command
then
commands
else
commands
fi
iftest-command;then
commands
else
commands
fi
下面的shell脚本,参数为文件名,该脚本将文件内容显示在终端上。如果第一个参数为'-v',该脚本将使用less命令分页显示。
if [ $# -eq 0 ]
then
echo “Usage:out [-v] filename...” 1>&2
exit 1
fi
if [ “$1” =“-v” ]
then
shift
less -- “$@”
else
cat -- “$@”
fi
在上面的脚本中,cat和less命令的'--'参数通知调用这些工具的命令行它后面再没有选项了,即不再把'--'后面以连字符开头的参数作为选项。‘rm-- -example.sh’(删除文件-example.sh).
shift和set对位置参数的操作。
if … then …elif:
if test-command
then
commands
eliftest-command
then
commands
…
else
commands
fi
示例:
echo -n “Word1:”
read word1
echo -n “Word2:”
read word2
echo -n “Word3:”
read word3
if [ “$word1”= “$word2” -a “$word1” = “$word3” ]
then
echo “Match: words 1,2 & 3”
elif [“$word1” = “$word2” ]
then
echo “Match: word 1 & 2”
elif [“$word2” = “$word3” ]
then
echo “Match: word 2 & 3”
else
echo “NoMatch”
fi
上面的脚本第一个if语句使用布尔操作符AND(-a)作为test的一个参数。注意'=''['和']'两边的空白符不可省略。
1#!/bin/bash
2#Identify links to a file
3# Usage:lnks file [directory]
4if [$# -eq 0 -o $# -gt 2 ]
5then
6echo"Usage:lnks file [directory]" 1>&2
7exit 1
8fi
9
10if [-d "$1" ]
11then
12echo"First argument cannot be a directory." 1>&2
13exit 1
14else
15file="$1"
16fi
17if [$# -eq 1 ]
18then
19directory="."
20elif [-d "$2" ]
21then
22directory="$2"
23else
24echo"Optional second argument must be a directory." 1>&2
25echo"Usage:lnks file [directory]." 1>&2
26exit 1
27fi
28
29#checkthat file exists and is a regular file:
30if [! -f "$file" ]
31then
32echo"lnks:$file not found or special file" 1>&2
33exit 1
34fi
35#checklink count on file
36set-- $(ls -l "$file")
37linkcnt=$2
38if ["$linkcnt" -eq 1 ]
39then
40echo"lnks : no other hard links to $file" 1>&2
41exit 0
42fi
43#get theinode of the given file
44set$(ls -i "$file")
45
46inode=$1
47#findand print the files with that incite number
48echo"lnks:using find to search for links..." 1>&2
49find"$directory" -xdev -inum $inode -print
50
黑体黄底命令行使用了命令替换$(command)
确定shell,用法消息,注释,测试参数。
内置命令set使用命令替换机制把位置参数设置为ls-l命令的输出。输出的第二个字段就是链接的数目,因此就将linkcnt就被设置为$2。set中的参数'--'防止把'-ls-l'(第一个输出字段是对文件的访问许可,一般以字符‘-’开头)产生的信息作为选项。
比较与文件名关联的inode来确定多个文件名是否链接到同一个文件,这是一种好方法。
find工具用于查找满足其参数所指定条件的文件,查找的位置由第一个参数($directory)指定并搜索其所有子目录。余下的参数指定把值为$inode的文件的文件名送到标准输出。由于不同文件系统中的文件可能拥有相同的inode号,并且没有链接,find必须只查找同一文件系统中的目录。参数-xdev防止find命令搜索其他文件系统。
可以使用-x选项来帮助调试脚本。该选项使得shell执行每条命令前把命令显示出来。
可以在带参数'-x'的shell中运行上面的shell脚本,在执行每条命令前先将该命令显示出来。要么为当前shell设置'-x'选项(使用set-x命令),以使所有脚本的命令在执行前都显示出来。要么只在当前执行脚本中通过shell使用'-x'选项。
>bash-x lnks.sh example
脚本中的每条命令前都会加上PS4变量的值,默认是加号'+'.因此可通过该值来区分是脚本输出还是调试输出。
通过在脚本的开始位置加入带有'-x'参数的set,就可以设置运行该脚本的shell。'set-x'
若要关闭调试则引应使用命令:'set+x'
'set -x' 同'set -xtrace'
控制结构for...in的语法如下:
for loop-indexin argument-list
do
commands
done
依照argument-list中的每个参数(将对应的每一个参数赋值给loop-index变量)重复执行do和done语句之间的命令。
例子1:
1forfruit in apples oranges pears bananas
2do
3echo "$fruit"
4done
例子2:
1for i in *
2do
3if[ -d "$i" ]
4then
5echo"$i"
6fi
7done
'*'匹配当前目录下所有可见文件名,与运行该shell脚本的当前目录有关,而与shell脚本所在目录无关。
for控制结构语法如下:
for loop-index
do
commands
done
loop-index用命令行参数中的每个参数值取代,重复执行do和done之间的语句。除了参数来源不同,该结构语法同'for...in'结构语法。
例子:
>cat -nfor_test.sh
1for arg
2do
3echo"$arg"
4done
5
>chmod a+rwxfor_test.sh
>./for_test.sh example example2 example4 example6
'forarg'隐含表示'forarg in “$@”',这里将”$@”扩展为一个命令行参数列表,如”$1””$2””$3”等。
>cat -nwhos.sh
1#!/bin/bash
2#adapted from finger.sh by Lee Sailer
3#UNIX/WORLD
4
5if [ $#-eq 0 ]
6then
7echo"Usage: whos id ..." 1>&2
8exit 1
9fi
10
11for id
12do
13gawk-F: ' {print $1,$5} ' /etc/passwd |
14grep-i "$id"
15done
16
>./whos.shroot “terry Zeng”
脚本whos演示了for结构中$@符号所代表的含义。whos脚本后面可以跟一个或几个用户名作为参数,执行whos脚本就可以将这些与用户相关的信息显示出来。
在这个脚本中的for循环中隐含的$@的使用特别有效果,因为它使得for循环可以把带空格的参数视为一个单独的参数(如参数”terry Zeng”)。
对于每个命令行参数,whos搜索/etc/passwd文件。在for循环结构中gawk的作用是从文件/etc/passwd的行中提取第一个($1)和第5个($5)字段的内容。第1个和第5个字段的内容通过一个管道传递给grep。grep在其输入中搜索内容为$id($id就是输入的命令行参数)的对象。选项'-i'的作用是让grep在搜索过程中忽略其他的事件,grep在其输入中按照每行的格式显示包含$id内容的对象。
行末的| 即便在管道标志后面还有换行,管道也能照常工作。
while:
while控制结构语法如下:
whiletest-command
do
commands
done
只要测试条件的返回值为真,while结构语句就要执行do与done语句之间的命令。
例子:
>cat -ncount.sh
1#!/bin/bash
2number=0
3while ["$number" -lt 10 ]
4do
5echo -n"$number"
6((number+= 1))
7done
8echo
test内置命令:脚本使用了'-lt'来执行数值比较测试。对于数值比较测试由以下几种测试选项:'-ne','-eq','-gt','-ge','-lt','-le'。对于字符串的比较可以用'='或者'!='来进行测试比较。
使用'-n'选项用来防止echo在其输出之后输出换行。最后的echo使脚本在标准输出上输出一个新的字符行。((number+= 1))赋值表达式。
例子:
1#!/bin/bash
2# removecorrect spellings from aspell output
3
4if [ $#-ne 2 ]
5then
6echo"Usage spell_check.sh file1 file2" 1>&2
7echo"file1 list of correct spellings" 1>&2
8echo"file2 file to be checked" 1>&2
9exit 1
10fi
11
12if [! -r "$1" ]
13then
14echo"spell ..check; $1 is not readable" 1>&2
15exit 1
16fi
17
18if [ !-r "$2" ]
19then
20echo"spell ..check; $2 is not readable" 1>&2
21exit 1
22fi
23
24aspell-l < "$2" |
25whileread line
26do
27if !grep "^$line$" "$1" > /dev/null
28then
29echo$line
30fi
31done
32
上面的脚本中'-r'参数判断一个文件是否是可读的,括号里的感叹号是对跟着的操作符进行相反的运算,与'-r'参数联合起来用以判断一个文件是否是不可读的。
上面的脚本把aspell脚本的输出(使用参数-l可以让aspell脚本把所检查出的错误单词的列表送到标准输出上)通过一个管道送到while结构的标准输入上,while结构从他的标准输入上一次读入一行内容(每行只有一个单词)。只要测试条件(也就是readline)能从标准输入上得到一个单词,那么它就返回一个true状态。
在while循环中if语句用来检测grep条件测试的返回值,grep是用来判断被读取行是否在用户的正确单词列表中。grep搜索的模式(也就是$line)前后都有特殊字符,这些字符分别用来指明一行的开始和结束(分别是'^'和'$';'^$line$'理解为'^---$line---$'其中'^'代表行的开始,第一个'$'代表对变量'line'的引用,第二个'$'代表行的结束)。这些特殊符号的作用是确保grep搜索时只有当变量$line的内容与用户输入的正确单词列表的一整行的内容相同时才形成匹配。grep的标准输出被重定向到文件/dev/null中,因为我们不关心输出结果,只关心返回状态。
' if ! grep "^$line$" "$1" > /dev/null '可以替换为'if ! grep -qw “$line” “$1”'。其中'-q'抑制了grep的输出,这样只返回退出状态。'-w'使得grep只匹配整个单词。
until
until与while语句的语法结构相似。区别仅在于条件语句的测试位置:一个在语句的开始测试,一个在语句的结束测试。
untiltest-commands
do
commands
done
例子:
1#!/bin/bash
2secretname=jenny
3name=noname
4echo"Try to guess the secret name!"
5echo
6until ["$name" = "$secretname" ]
7do
8echo -n"Your guess:"
9readname
10done
11echo"Very good."
12
例子:
1#!/bin/bash
2#UNIX/WORLD
3trap ' '1 2 3 18
4stty-echo
5echo -n"Key: "
6readkey_1
7echo
8echo -n"Again:"
9readkey_2
10echo
11key3=
12if ["$key_1" = "$key_2" ]
13then
14tputclear
15until[ "$key_3" = "$key_2" ]
16do
17readkey_3
18done
19else
20echo"locktty: keys do not match" 1>&2
21fi
22sttyecho
23
如果运行上面的例子而忘记了脚本密码,可以登录另一个虚拟终端并终止该进程。
trap内置命令:利用trap内置命令可以防止用户通过发送中断的方式来终止脚本的运行。通过捕获信号18可以保证用户无法用CONTROL+Z组合键来挂起运行该脚本的进程。stty-echo命令来防止终端把键盘输入的字符显示出来,这样可以保证输入的密码不被显示出来。
break与continue:同c语言可以用来中断forwhile until语句的执行
1#!/bin/bash
2forindex in 1 2 3 4 5 6 7 8 9
3do
4if [$index -le 3 ]
5then
6echo"continue"
7continue
8fi
9echo$index
10if [$index -ge 8 ]
11then
12echo"break"
13break
14fi
15done
16
case:一种多分支选择机制,同C语言。
casetest-string in
pattern-1)
commands-1
;;
pattern-2)
commands-2
;;
pattern-3)
commands-3
;;
...
esac
case结构中的匹配类型类似于一个模糊文件引用。
字符‘*’:匹配任意字符串,用作默认的case匹配。
字符‘?’:匹配 单个字符。
[…]:定义一个字符类,对处于方括号中的每个字符依次进行单字符匹配;两个字符之间的连字符用来指定字符范围。
| :分离带有选择的选项,这些选项满足case结构的一个特别的分支。
例子:
1echo -n"Enter A,B,or C:"
2readletter
3case"$letter" in
4a|A)
5echo"You Entered A"
6;;
7b|B)
8echo"You Entered B"
9;;
10c|C)
11echo"You Entered C"
12;;
13*)
14echo"You did not enter A,B,or C"
15;;
16esac
例子:
1#!/bin/bash
2
3echo-e "/n COMMAND MENU/n"
4echo"a.Current date and time"
5echo"b.Users currently logged in"
6echo"c.Name of the working directory"
7echo-e "d.Contents of the working directory/n"
8echo-n "Enter a,b,c,or d:"
9readanswer
10echo
11case"$answer" in
12a)
13date
14;;
15b)
16who
17;;
18c)
19pwd
20;;
21d)
22ls
23;;
24*)
25echo"There is no selection:$answer"
26;;
27esac
'echo -e'选项-e使echo把后面的'/n'解释为一个换行符,如果echo后面不加这个参数'-e',echo就会输出两个字符'/n',而不是一个空行。参数'-e'使得echo解释由反斜杠'/'转义的字符。带有反斜杠的字符一定要引起来,否则反斜杠就要由shell来解释而不会传到echo由echo解释。
例子:
>cat -nsafedit
1#!/bin/bash
2PATH=/bin:/usr/bin
3script=$(basename$0)
4case $#in
50)
6vim
7exit 0
8;;
91)
10if [ !-f "$1" ]
11then
12vim"$1"
13exit0
14fi
15if [ !-r "$1" -o ! -w "$1" ]
16then
17echo"$script:check permissions on $1" 1>&2
18exit1
19else
20editfile="$1"
21fi
22if [ !-w "." ]
23then
24echo"$script:backup cannont be"/
25"createdin the working directory" 1>&2
26exit1
27fi
28;;
29*)
30echo"Usage:$script [file-to-edit]" 1>&2
31exit 1
32;;
33esac
34
35tempfile=/tmp/$$.$script
36cp$editfile $tempfile
37if vim$editfile
38then
39mv$tempfilebak.$(basename $editfile)
40echo"$script:backup file created"
41else
42mv$tempfileediterr
43echo"$script:edit error--copy of" /
44"originalfile is in editerr"1>&2
45fi
46
>chmod u+xsafedit
>./safeditexample.sh
再另一个控制台上进入tmp目录可以查看到一个nxxn.safedit的临时文件,回到原来的控制台退出vim编辑器,查看当前控制台当前工作目录下会生成一个备份文件格式bak.example.sh。再打开新的控制台查看/tmp目录发现最开始生成的临时文件已经被删除。
>ln safeditsafedit.ln
>./safedit.lnexample.sh
注意观察该命令行运行的过程,生成的中间文件,最后结果与上面文字描述的不同。
设置PATH变量:该脚本设置了PATH变量,目的是为了保证脚本中执行的命令是系统目录中的标准命令。避免了用户自己可能设置的PATH包含自己定义的目录,而在该自定义目录下,用户可能编写了一些与脚本中调用命令同名的脚本或程序。
程序名:basename去掉前导的目录部分后打印名称,因此脚本中将script设置为运行脚本的基本名称。通过命令替换实现。$0存储脚本被调用时的命令。好处在于对脚本进行重命名或则创建链接后运行该脚本会得到正确的提示信息。
给临时文件命名:脚本中设置变量tempfile为临时文件名,以shell进程的PID号作为开始并以脚本的名字作为结束。使用PID号是为了确保文件名的唯一性,脚本名字附在临时文件名后面,为了让用户知道其来源。PID号放在前面是由于一些老版本unix上对文件名有长度限制,而PID号可以确保其唯一性,所以放在前面避免由于文件名字长的限制而被切去。
测试条件:脚本中使用了一个测试条件vim$editfile。测试vim编辑器编辑文件完成后返回的exit代码,if控制结构就是利用这个exit代码来决定分支。成功则返回0,then被执行;不成功则返回非0,else语句被执行。
select:首先显示一个菜单,然后根据用户的选择给变量赋予相应的值,最后执行一系列命令。
select varname[in arg ….]
do
command
done
例子:
1#!/bin/bash
2PS3='Chooseyour favorite fruit from these from these possibilities:'
3selectFRUITin apple banana blueberry kiwi orange watermelon STOP
4do
5if ["$FRUIT" = "" ];then
6echo-e "Invalid entry./n"
7continue
8elif ["$FRUIT" = STOP ];then
9echo"Thanks for playing."
10break
11fi
12echo"You Chose $FRUIT as your favorite."
13echo -e"That is choice number $REPLY./n"
14done
15
PS3:是select特有的提示符,在select语句输出菜单后,就会显示出PS3的值。slect不断的发出PS3提示并按照用户的输入执行命令,直到有事情使其停止。
select将varname设置为输入的值(例子中是变量FRUIT),同时将用户的响应存储在键盘变量REPLY中。如果用用户非法输入,shell将varname设置为空($FRUIT)。
- linux_shell笔记(八)
- linux_shell笔记(一)
- linux_shell笔记(二)
- linux_shell笔记(三)
- linux_shell笔记(四)
- linux_shell笔记(五)
- linux_shell笔记(六)
- linux_shell笔记(七)
- linux_shell笔记(九)
- linux_shell笔记(十)
- linux_shell编程学习笔记
- linux_shell
- linux_shell脚本
- Linux_Shell基础
- linux_shell学习总结(2)...
- linux_shell及常用命令介绍
- linux_shell常见实例
- linux_shell 特殊符号的介绍
- org.eclipse.swt.SWTException: Invalid thread access
- 引用其它插件的图片
- 一msdn地址 http://www3.upweb.net/index274-img/showlog.php?id=6406
- 10-05-01
- 软件测试概述
- linux_shell笔记(八)
- 大国际时代重新开启
- 对枚举、接口、结构的理解
- 人生需要放下的八样东西
- PermGen space error
- MySQL中的时间操作
- EI和ISTP双检索的会议推荐给大家:2010 IEEE 多媒体信息网络与安全国际会议 (MINES2010)
- java中equals和==的区别
- 如何在当前Eclipse的Console View中输出信息