Who am I

我的照片
Hefei, Anhui, China
Research Fields: Satellite Geodesy
显示标签为“Shell”的博文。显示所有博文
显示标签为“Shell”的博文。显示所有博文

2012年2月14日星期二

Shell eval, expr, bc命令

eval命令
作用:首先扫描命令行进行所有的替换,然后再执行命令。用于那些一次扫描无法实现其功能的变量,该命令对变量进行两次扫描。


用法:eval command 


举例:
1. 两次扫描(先替换,后执行)
有一文件,名为test.txt,内容为hello shell world!
变量myfile="cat test.txt"
echo $myfile          显示结果为:cat test.txt
eval echo $myfile    显示结果为:hello shell world!


2. 获取最后一个参数
eval echo /$$#
第一遍扫描去掉/,shell再次执行时,$#是参数个数,$($#)是最后一个参数


expr命令
作用:用于简单的整数计算和字符串操作。
用法:expr expression
举例:
整数运算:
expr 14 % 9           5
expr 10 + 10          20
expr 1000-900        100
expr 1000/10          100
expr 10 /* 100        1000 (使用*时,需用/进行转义)


字符串操作:
计算字符串长度    expr length "this is a test"          结果为:14
抓取子字符串       expr substr "this is a test" 3 5     结果为:is is
获取第一个字符出现的位置  expr index "sarasara" a    结果为:2
字符串重现          expr quote sara                       结果为:sara


增量计数:
LOOP=0
LOOP=`expr $LOOP+1`


模式匹配
使用expr通过制定冒号选项计算字符串中的字符数。
VALUE=account.doc
expr $VALUE : '.*'    结果为8,变量VALUE中一共有8个不同的字符
expr $VALUE : '[0-9]*'   计算字符串中的数字个数

2012年2月13日星期一

Shell awk命令

awk命令
简介
awk是一种样式扫描与处理工具,它是三个人名的首字母缩写。它几乎可以完成grep和sed所能完成的全部工作,同时它还可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。当前有awk,nawk和gawk三个版本。

特点
1. awk不同于sed,不自动输出行;
2. awk不使用单个字符的选项来控制输出,而是通过一系列函数来控制输出;
3. awk含有大量的内置函数和语句(大多类似于C语言),使得awk更像一门编程语言,处理问题的能力大大增强。


用法
awk有两种调用方法:在命令行中指定编辑指令;将编辑指令存储到一个文件中,在awk命令中调用该文件。
方法1: awk [options] '/pattern/{actions}' files
方法2: awk [options] -f scriptfile files (其中scriptfile中是/pattern/{actions}的集合)


选项
-F      更改字段分隔符(默认为空格或tab)  -F; 将字段分隔符设定为;
-f       调用scriptfile文件
-v      调用shell变量;
-v var=$shell_var; 此后,在awk中可以直接用var($可省略)代替$shell_var; 每引用一个shell_var都要使用一下选项-v


pattern和actions(awk语句的重要组成部分)
1. pattern包含以下任意内容
选定文本范围(正则表达式;指定行号和范围,同sed);
关系表达式:<, >, <=, >=, ==, !=, 此外还包括两种匹配模式,如下
                value ~ /pattern/     value匹配pattern则为真
                value !~ /pattern/    value不匹配pattern则为真
复合表达式:可以是文本范围匹配和关系表达式的任意组合,&&, ||, 其中每个子表达式需用()括起来
BEGIN模式: 让用户指定在第一行文本被处理之前所发生的动作(通常在这里可以设置全部变量)
END模式: 让用户在最后一条记录被读取之后发生的工作


2. action
由一个或多个命令、语句、函数、表达式组成,之间用换行符或分号隔开,并用{}括起来。主要有四部分内容:
变量或数组赋值;
输出命令;
内置函数;
控制流命令(条件控制;循环控制)
注:pattern可选,若没有指定pattern为输入文件的每一行执行actions


变量
设置变量 
fruit=apple         将fruit变量值设为apple
myfruit=fruit       将变量myfruit设置为变量fruit的值(故fruit和myfruit都被设置为apple)
fruit=$1             将变量fruit设置为每一行的第一个字段
此外,+=,-=,*=,/=,%=,^=这样的赋值操作符用于改变变量的值




内置变量
FILENAME          当前输入文件的文件名,不应改变该变量的值;
NR                    当前行的编号,不应改变该变量的值;
NF                    当前行中域的编号,不应改变该变量的值;
OFS                  输出域分隔符(缺省为空格)
FS                    输入域分隔符(缺省为空格或tab键)
ORS                  输出记录分隔符(缺省为换行符)
RS                    输出记录分隔符(缺省为换行符)
$0                    当前行的全部内容
$1,$2,...            当前行的第一个字段,第二个字段,等等


if语句
f (expression1) {
       action1
} else if (expression2) {
       action2
} else {
       action3
}


while语句
while (expression) {
          actions
}

do语句
do 
{
           actions
}  while (expression) 

for语句 

for (initialize_counter; test_counter; increment_counter) {
           actions
}


next命令
作用:跳出剩余的语句
例: awk '$3 <= 75 {printf "%s%t%s\n",$0,"REORDER"; next; }  #若满足该条件,下面的语句不执行
             $3 > 75 {print $0;}' test.txt
      
举例
1. awk '{print;}' test           打印test文件的每一行(;不可省)
2. awk '{print $1 $2;}' test   打印test文件每一行的第一和第二个字段,输出结果没用分隔符分割
3. awk '{print $1,$2;}' test   打印test文件每一行的第一和第二个字段,输出结果用空格分割
4. awk '{printf "%-32s %s\n",$1,$2;}' test   利用printf格式化输出(同C语言)
5. awk '/ *\$[1-9][0-9]*\.[0-9][0-9] */ {print $0,"*"}' $0原原本本地输出匹配到的内容
6. BEGIN和END模式
awk '
       BEGIN {printf "%s\t", FILENAME;}
       /^ *$/ {x+=1;}
       END {ave=100*x/NR; printf "%s\t%3.1f\n", x,ave;}
      ' test.txt
7. 改变FS(域分隔符)
awk -F: '{print $1, $3;}' test.txt
awk 'BEGIN {FS=":";}{print $1,$6;}' test.txt

Shell sed命令

sed命令
简介
sed(stream editor)是一个可用于过滤文本的流编辑器,sed逐行处理文件(或标准输入)并把处理后的内容输出到屏幕或重定向输出到文件中。


特点
1. 非交互式文本流编辑器,它读取文件或标准输入的一行并将其存储在临时缓冲区中,sed命令处理临时缓冲区中的内容,完成后把缓冲区的内容输出。处理完一行后再读取下一行。因此,sed是对文件的拷贝进行编辑和修改,不会修改和破坏源文件
2. sed通过行号正则表达式指定要改变的文本行。
3. sed默认将每个输入的行都打印出来(被修改的行再打印一遍)


用法
sed有两种调用方法:在命令行中指定编辑指令;将编辑指令存储到一个文件中,在sed命令中调用该文件。
方法1: sed [options] '/pattern/actions' files
方法2: sed [options] -f scriptfile files (其中scriptfile中是/pattern/actions的集合)


选项
-e    允许在一个命令行中给出多个编辑指令
如  sed -e 's/ MA/, Massachusetts' -e ' s/ PA/, Pennsylvania/' file
注:在一个命令行中指定多个编辑指令还有其它两种方法:
用分号分隔指令: sed 's/ MA/, Massachusetts/; s/ PA/, Pennsylvania/' file
用分行提示符(>):sed ‘
                      > s/ MA/, Massachusetts/
                      > s/ PA/, Pennsylvania/
                      > s/ CA/, California/'    file
-n     阻止输入行的自动输出
-f      跟随脚本的文件名


定位文本(通过行号和pattern)
x                         指定行号
x,y                       行号范围
/pattern/               查询包含模式的行
/pattern1/pattern2/ 查询包含两个模式的行
/pattern/,x             在指定行号上查询匹配模式的行,从第一个匹配pattern的行到x行之间
x,/pattern/             通过行号和模式查询匹配行,从x行开始到第一个匹配pattern的行之间
x,y!                       查询不包含行号x,y的行


动作(actions)
d       删除行
p       打印文本
!        对所选行之外的所有行应用命令
=       打印行号
s        替换文本(s/west/north/,替换每行出现的第一个west;s/west/north/g,替换每行所有的west)
r        从文件中读取行内容
w       按行写入新文件
a\      在当前行后添加一行或多行
i\       在当前行之前插入文本
c\      用新文本代替当前行中的文本
q       退出sed
y       将一字符转换成另一字符


实例
d命令
sed '2d' test            删除test文件的第二行
sed '2,$d' test          删除test文件的第二行到末尾所在行
sed '$d' test             删除test文件的最后一行
sed ’/test/d’             删除test文件中所有包含test的行


p命令
sed '/fruit/p' test      打印包含"fruit"的行,但是其它所有的行业会默认输出一遍
sed -n '/fruit/p' test  只打印包含"fruit"的行


s命令
sed 's/test/mytest/g' example     在整行范围内把test替换为mytest
sed -n 's/test/mytest/g' example 只打印那些发生替换的行
sed 's/^192\.168\.0\.1/&localhost/' example &表示替换字符串中被找到的部分。结果变成192.168.0.1localhost


r命令
sed '/test/r file' example      file里面的内容被读进来,显示在与test匹配的行后面;如果匹配多行,则file的内容将显示在所有匹配行的下面。


w命令
sed -n 'test/w file' example  在example文件中所有包含test的行都被写入file里。


a命令
sed '4a\this is a test' example  在example文件中的第四行加入“This is a test”
sed '4,6a\this is a test' example 在example文件中的第4,5,6行后都加入“This is a test”
sed '/hello/a\this is a test' example 在example文件中匹配hello的行后都加入"This is a test"


i命令
sed '4i\this is a test' example   在example文件的第四行之加入“this is a test”
sed ’/hello/i\this is a test‘ example 在example文件中匹配hello的行之前都加入“this is a test”


c命令
sed '4c\this is a test' example  把example文件中第四行改成this is a test
sed '/hello/c\this is a test' example 把example文件中匹配hello的行都改成“this is a test”


=命令
sed '/hello/=' example    显示example文件里匹配hello字符的所有行的行号


q命令
sed '/hello/q; s/Hello/hello/g' example  打印匹配hello行后即退出sed命令,不执行后面的替换命令


!命令
sed '/hello/!d' example    把example文件中不含hello的行打印出来

2012年2月11日星期六

Shell 正则表达式

shell正则表达式
一个正则表达式是由普通字符以及特殊字符(也称元字符)组成的匹配模式。把该模式与数据文件、其它命令的输出等对象进行匹配。
注:区分shell正则表达式中的元字符与shell命令中的通配符,两者不同,切勿混淆。

shell元字符

^        行首定位符(当^位于正则表达式的第一个字符时,它表示行首定位符;否则,它匹配字符^)
/^Bobby/
Here is a tongue twister:
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.

$         行尾定位符(当$位于表达式的最后一个字符时,表示行尾定位符;否则匹配字符$)
/Bobby$/
But so boldly Bobby banged it
That he burst his rubber ball, "Boo!" cried Bobby

/^$/      匹配一个空行

\<        词首定位符
/\<Bo/
That he burst his rubber ball,"Boo!" cried Bobby
Bobby Bippy bought a ball.

\>        词尾定位符
/ball\>/
Bobby Bippy bought a ball

在一个表达式搭配使用词首定位符与词尾定位符
/\<hole\>/
John's ball fell into the hole
John cried because it is his whole life

.         匹配任何除换行符之外的单个字符(换行符的匹配模式/\n/)
/B...y/
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.

[]       匹配一组字符里的任意一个字符(不管[]的形式多复杂,它只匹配一个字符)

[abc]   匹配单个字符a或b或c
/[bw]all/
WIth his bat Bob banged the ball
Banged it bump against the wall

[a-z]  匹配小写字母a-z之一
[a-z A-Z 0-9] 匹配任意英文字母或数字之一-字符出现在[]的首或尾位置时是普通字符
/B[a-z]p/
Bobby Bippy bought a bat.
Bobby Bippy bought a ball.

[^]     匹配不在指定范围内的字符(区别与行首定位符,一定是在[]的首位置出现)
[^ab^c]     匹配不是a或b或^或c的任意一个字符
/all[^a-z A-Z 0-9]/     匹配all后加有一个特殊字符的字串
Bobby Bippy bought a ball.
Bad luck ball, Bad luck Bobby, bad luck ball.

前导字符
*  \  \?  \+  \{n,m\}       所谓前导字符,表示紧贴于元字符前面的单个普通字符或上面所述的元字符。
*      用于修饰前导字符,表示前导字符出现任意多次(包括0次)
\       转义字符
\?      用于修饰前导字符,表示前导字符出现0或1次
\+      用于修饰前导字符,表示前导字符出现1次或1次以上
\{n,m\} 用于修饰前导字符,表示前导字符出现n至m次
a*      匹配连续的任意(也包括0个)a
例:
/al*/
Bobby Bippy bought a bat.
With his bat Bob banged the ball
.*       匹配连续的任意(也包括0个)任意字符,也称万能匹配
a\?      匹配0或1个a
a\+      匹配1或多个a
a\{3,5\}  匹配3至5个连续的a
\.*       匹配0个或多个连续的.
此外,\{n,m\}还有其它几种形式:
\{n\}    匹配连续的n个前导字符
\{n,\}   匹配至少连续的n个前导字符
\?等价于\{0,1\}  *等价于\{0,\}   \+等价于\{1,\}

一些例子
[0-9]\{2\}       连续的两位数字
[0-1][0-9][-/][0-3][0-9][-/][0-9]\{2\}    表示时间格式MM-DD-YY或MM/DD/YY
80[234]\?86     将匹配8086,80286,80386,80486
/\<Bob.*all\>/
Bobby Bippy bought a ball
With his bat Bob banged the ball

扩展模式匹配
*(模式表)    匹配给定模式表中的”模式“0次或多次,各模式之间用|分开。
file*(.c | .o) 将匹配文件file file.c file.o file.c.c file.o.o file.c.o file.o.c等,不匹配file.h或file.s等
+(模式表)    匹配给定模式表中的”模式“1次或多次,各模式之间用|分开。
file+(.c | .o) 匹配file.c file.o file.c.c file.o.o file.c.o file.o.c等,但不匹配file
?(模式表)     匹配模式表中的”模式“0次或1次,各模式之间以|分开。
file?(.c | .o) 只匹配file file.c 和file.o
@(模式表)    匹配模式表中给定”模式“的一次出现,各模式之间以|分开。
file@(.c | .o) 匹配file.c file.o
!(模式表)      除给定模式表中的模式之外,它可以匹配其它任何一个。

Shell cut命令

cut命令
简介:正如其名,cut命令的功能就是“剪”,具体说来就是截取每行中的特定内容,并输出。操作对象是每一行
用法:cut [options]num1-num2 files
选项:-b  以字节为单位,截取num1至num2字节间的字符(一个汉字算三个字节)
      -c  以字符为单位,截取num1至num2字符间的字符(一个汉字算一个字符)
      -f  按域为单位,截取num1至num2域之间的内容,按域去字符时,通常要指定域分割符,用-d选项指定域分隔符,如-d:,用:作为域分割符(默认为tab符)
      -s  如果行中没有分割符,则不打印该行
举例:
1. -b选项
[root@localhost ~]# date
2011年08月11日 星期四20:44:52 EDT
[root@localhost ~]# date |cut -b 1-4                取前四个字节
2011
多个定位之间用逗号隔开:
[root@localhost ~]# date |cut -b 1-7,10
2011年8
[root@localhost ~]# date |cut -b 10,1-7       -b后面所有的定位进行从小到大排序,然后再提取
2011年8
负号的使用:
[root@localhost ~]# date |cut -b -4        第一个字符第四个字符
2011
[root@localhost ~]# date |cut -b 4-        第四个字符最后一个字符
1年08月11日 星期四21:05:30 EDT
[root@localhost ~]# date |cut -b -4,4-
2011年08月11日 星期四21:06:53 EDT
这两种情况下,都包括了第4个字节“1”,会输出整行,不会出现连续两个重叠的1
2. -c选项
[root@localhost ~]# date |cut -c 1-5
2011年
[root@localhost ~]# date |cut -c 5,9,13
年月日
3. -f选项
以/etc/passwd文件为例:
[root@localhost ~]# head -n5 /etc/passwd |cut -d : -f 1,3-5
root:0:0:root
bin:1:1:bin
daemon:2:2:daemon
adm:3:4:adm
lp:4:7:lp
-d指定域分隔符,-f 指定要剪出哪几个域。-d选项的默认间隔符就是制表符。
cut -d: -f1,5  /etc/passwd 用冒号作为分隔符打印文本列,显示第一和第五列
cut -d: -f1-5 /etc/passwd 用冒号作为分隔符打印文本列,显示第一到第五列
cut -d: -f5-  /etc/passwd 用冒号作为分隔符打印文本列,显示第五列及其之后的列


2012年2月10日星期五

Shell中的tr,sort和uniq命令

tr命令
简介:可以快速实现字符的简单转换,也可以删除字符串中的指定字串,合并字符串中的重复串。
用法:tr [option] "set1" "set2"
选项:-c    用set1中的字符串替换,要求字符集为ascii(默认选项)
     -d     删除set1中的字符,而不是转换
     -s     删除所有重复出现的字符序列,只保留第一个;即将重复出现的字符串压缩为一个字符串。
     -t     把set1中的字符依次替换成set2中的字符
举例:
1. ls | tr "\n" " " 将换行符替换成空格
2. tr f F < aa.txt 将aa.txt文件中的字符f替换成F
3. ls | tr -d '\n' 删除换行符
4. tr -d f < aa.txt 删除文件中所有的f
5. tr [a-z] [A-Z] < aa.txt 将aa.txt中的所有小写字符替换成对应的大写字母
6. echo "feed me" | tr -s "e"   显示结果为fed me,删除重复字符

7. echo "a ab ac" | tr -t [a-c] [0-2] 显示结果为 0 01 02

sort命令
简介:将文本文件内容加以排序
用法:sort [bcdfimMnr][-o输出文件][-t分隔字符][文件]
选项:-b     忽略每行前面开始处的空格字符
     -c     检查文件是否已经按照顺序排序
     -d     排序时,处理英文字母、数字及空格字符外,忽略其它的字符
     -f     排序时,将小写字母视为大写字母
     -i     排序时,除了040至176之间的ascii字符外,忽略其它的字符
     -m     将几个排序好的文件进行合并
     -M     将前面3个字母依照月份的缩写进行排序
     -n    依照数值的大小排序
     -o    将排序后的结果存入指定的文件
     -r    以相反的顺序来排序
举例:
1. sort -r < aa.txt
2. sort -nr < aa.txt
3. sort -nr -obb.txt <aa.txt
4. tr "!?":;\[\]{}(),.\t\n" " " < test.txt    #将所有标点符号换成空格符
   tr [A-Z] [a-z] | tr -s " " | tr " " "\n" | sort   #将所有大写字母换成小写字母,并删除重复      的空格字符,将空格符替换成换行符,按行排序

uniq命令
简介:检查及删除文件中重复出现的行
用法:uniq [options] file_in file_out
选项:-c    重复行只显示一次,但在每行的左边显示该行在文档中重复的次数
     -d     只显示重复行,并只显示一次
     -u     只显示不重复行
     file_in 输入的文件名
     file_out 将显示结果输出到文件
举例:
1. uniq -c test.txt
2. uniq -d test.txt
3. uniq -u test.txt
4. uniq -c test.txt test_new.txt


Shell grep命令

grep是global regular expression print的缩写,使用户可以在文件中查找包含某个单词或词组的行。


grep的基本语法
grep [options] pattern files
其中:pattern可以是使用正则表达式的模式匹配符或者就是一个word;files可以是一个文件或多个文件序列(搜索结果中会给出对应的文件名),也可以为空(当没有提供files时,默认搜索当前目录下的所有文件)。
两个特例:
grep pattern1 | pattern2 files      显示匹配pattern1或pattern2的内容
grep pattern1 files | grep pattern2 显示即匹配pattern1又匹配pattern2的内容

常用选项:
-c     只输出匹配行的计数,不显示匹配行的内容  
-i     匹配文本时忽略大小写
-l     只列出匹配的文件名
-L     列出不匹配的文件名
-v     显示不包含匹配文本的所有航
-n     显示匹配行及行号
-d     后接的不是文件,而是一个目录
-H     显示文件名和行号(若有路径,会显示路径)
-h     不显示匹配行所在的文件名
-r     不仅搜索当前目录,还搜索目录下的子目录
-w     只匹配单词,而不是单词的一部分(如"magic"而不是"magical"的一部分)

常用举例:
1. grep "sort" *.doc         在所有.doc文件里搜索含sort字符串的行,并打印
2. grep -c "48" data.doc     输出文档中含有48字符的行数
3. grep -n "48" data.doc     显示所有匹配48的行和行号
4. grep -vn "48" data.doc    输出所有不包含48的行
5. grep -i "ab" data.doc     输出所有包含ab或Ab,AB,aB的字符串的行
6. grep '[239].' data.doc    输出所有含有以2,3或9开头的,并且是两个数字的行
7. grep '^[^48]' data.doc    不匹配行首是48的行
8. grep '[a-z]\{5\}' aa      显示所有包含字符串至少有5个连续小写字符的字符串的行
9. grep -r                   明确要求搜索子目录
10.grep -d skip              忽略子目录

shell函数


shell函数的定义(两种方式):
function funcname{
          body
}
function funcname(){
body
}
其中,关键字function可以省略。两者的区别在于第二种加了()。通常使用第二种形式,类似于C语言风格。

shell函数的调用
shell语言不同于其它编程语言,shell语言不会进行预编译。因此,函数在使用之前必须进行预定义。函数的定义可以写在当前的shell脚本中,也可以写在单独的一个文件中。写在当前的shell文件中,在调用函数之前必须先写函数体。例:
#! /bin/bash
hello(){
echo “hello there today’s data is `date`”
}
hello          #调用函数hello
第二种方式是将函数体单独写在一个文件中,在shell脚本中包含这个函数即可。
shell使用source命令引用其它文件,类似于C语言的includesource命令等同于.命令。
source file_name     这样可以把函数定义在一个文件中,在另外一个文件中调用这个函数。
例:将函数hello写在文件hellofunc文件里。在一个新的脚本文件里调用这个函数
#! /bin/bash
. hellofunc        #(或者可以写成source hellofunc),调用hello函数
hello         #运行hello函数

参数传递
当一个函数被调用时,脚本程序的位置参数$*,$@,$#,$1,$2等会被替换为函数的参数。当函数执行完毕后,这些参数会恢复它们先前的值。
shell脚本与函数间的参数传递可利用(1)位置参数(2)变量直接传递。变量的值可以由shell脚本传递给被调用的函数。如下例所示
#! /bin/bash
func() {
echo $a $b $c
echo $1 $2 $3
}
a=”working directory”
b=”is”
c=`pwd`
func Welcome you baby
显示结果为:
working directory is /home/wuhu
Welcome you baby

函数返回
如果在函数里没有使用return命令指定一个返回值,函数返回的就是执行的最后一条命令的退出码。因此,可以通过return命令让函数返回数字值;让函数返回字符串值的常用方法是让字符串保存在一个变量中,而该变量应该可以在函数结束之后被使用。
例:
#! /bin/bash
function hello(){
          echo “Hello!”
}
hello          #调用函数
echo $?     #查看函数执行状态,0代表成功执行,1代表错误。

函数的载入和删除
set命令查看已载入的函数
unset funcname取消载入
例:
#! /bin/bash
. hellofunc
unset        #取消载入
        hello        #因为已经取消载入,所以调用会出错

shell文件描述符


文件描述符是将一个数字和一个文件名相关联起来的机制,然后使用这个编号向该文件进行读写。有时,文件描述符又称为文件句柄
标准输入(STDIN),0;标准输出(STDOUT),1;标准错误(STDERR),2
command n>file; command n>> file
标准输出重定向:command 1>filecommand 1>>file
标准输入重定向:command 0<file;
command 1>file1 2>file2:STDOUT重定向到file1STDERR重定向到file2

exec绑定重定向
上面所讲的输入输出重定向只对当前的指令有效,当需要多次将输入输出重定向到一个文件时,可以利用exec命令。格式如下:
输出重定向:
exex n>file exec n>>file
这里n是一个整数,文件file是打开的需要写入的文件。例:exec 4>fd4.out   fd4.out与文件描述符4相关联。
输入重定向:
exec n<file
STDOUTSTDERR重定向到一个文件
command >file 2>&1

使用文件描述符
cmd >&n           把输出送到文件描述符n
cmd m>&n        把输出到文件描述符m的信息重定向到文件描述符n(如2>&1
cmd >&-            关闭标准输出(等同于cmd 1>&-
cmd n>&-          关闭标准输出文件描述符n
cmd <&n           输入来自文件描述符n
cmd m<&n        m来自文件描述符n
cmd <&-            关闭标准输入(等同于cmd 0<&-
cmd n<&-          关闭输入文件描述符n
cmd <&n-          移动输入文件描述符n而非复制它
cmd >&n-          移动输出文件描述符n而非复制它

简单重定向补充
cmd <<< word  只把word和后面的换行作为输入提供给cmd(区别here document
cmd <> file        以读写模式把文件file重定向到输入

举例说明
echo “11111” > a.txt 等同于echo “11111” 1>a.txt
>重定向到文件时,会将文件清空,再写入。
> 1.txt 等同于 :>1.txt   清空文件内容
( ls tank; pwd )&>1.txt        将错误信息,以及输出内容放到1.txt文件中
上述语句等同于( ls tank; pwd ) >1.txt 2>&1
<>用法举例:
echo 123456 >2.txt
exec 4<>2.txt         #打开2.txt并将内容读取到&4
read –n 4 <&4        #&4中读取4个字符
echo –n . >&4        #&4中写入一个点
exec 4>&-             #关闭输出文件描述符4
        cat 2.txt                                    #结果为12345.6

2012年2月8日星期三

getopts语句


getopts语句的语法:
getopts option-string variable
其中option_string中包含一个有效的单字符选项。若getopts命令在命令行中发现了连字符,那么它将用连字符后面的字符同option_string相比较。若有匹配,则把变量variable的值设为该选项。若无匹配,则variable设为?。当getopts发现连字符后面没有字符,会返回一个非零的状态值。Shell程序中可以利用getopts的返回值建立一个循环。
getopts对命令行给出的选项进行分析,过程如下:
ü  getopts检查所有命令行参数,找到以”-”字符开头的字符;
ü  当找到以”-”字符开头的参数后,将跟在”-”字符后的字符与在option-string中给出的字符进行比较;
ü  若找到匹配,指定的变量variable被设置成选项,否则,variable被设置成”?”字符;
ü  重复上面三项,直到考虑完所有的选项;
ü  当分析结束后,getopts返回非零值并退出。

下面代码说明了date命令中怎么使用getopts命令处理各种选项,该程序除了完成unix的标准命令date的功能外,还增加了许多新的选项。
#newdate
if [ $# -lt 1 ]
then 
date
else 
while getopts mdyDHMSTJjwahr OPTION
  do 
  case $OPTION in 
    m)date '+%m';;
      d)date '+%d';;
      y)date '+%y';;
      D)date '+%D';;
      H)date '+%H';;
      M)date '+%M';;
      S)date '+%S';;
      T)date '+%T';;
      j)date '+%j';;
      J)date '+%y%j';;
      w)date '+%w';;
      a)date '+%a';;
      h)date '+%h';;
      r)date '+%r';;
      \?)echo "无效的选项!$OPTION";;
    esac
  done
fi
$ newdate -J
  94031
$ newdate -a -h -d
  Mon
  Jan
  31
$ newdate -ahd
  Mon
  Jan
  31 

有时侯选项中还带一个值,getopts命令同样也支持这一功能。这时需要在 option_string中选项字母后加一个冒号
getopts命令发现冒号后,会从命令行该选项后读取该值。若该值存在,那么将被存在一个特殊的变量OPTARG中。额外参数和参数之间用空格隔开如果该值不存在,getopts命令将在OPTARG中存放一个问号,并且在标准错误输出上显示一条消息。
下面的例子,实现拷贝一个文件,并给文件赋一个新的名字。-c选项指定程序拷贝的次数,-v选项要求显示新创建文件的文件名。
# Syntax: duplicate [-c integer] [-v] filename COPIES=1   
VERBOSE=N
while getopts vc:OPTION 
do 
  case $OPTION in
      c)COPIES=$OPTARG;;
      v)VERBOSE=Y;;
      \?)echo "无效参数!"
        exit 1;;
    esac
  done
  if [ $OPTIND -gt $# ]
  then
    echo "No file name specified"
     exit 2
  fi
  shift 'expr $OPTIND - 1'
  FILE=$1
  COPY=0
  while [ $COPIES -gt $COPY ]
  do
    COPY='expr $COPY + 1'
    cp $FILE $ {FILE} $ {COPY}
    if [ VERBOSE = Y }
    then
      echo ${FILE} $ {COPY}
    fi
  done 
   输出结果为:
$ duplicate -v fileA
 fileA1
 $ duplicate -c 3 -v fileB
 fileB1
 fileB2
 fileB3