5ren--renamesanumberoffilesusingsedregularexpressions
6
7USAGE:
ren'regexp''replacement'files
8EXAMPLE:
renameall*.HTMfilesin*.html:
9ren'HTM$''html'*.HTM
10
11HELP
12exit0
13fi
14OLD="$1"
15NEW="$2"
16#Theshiftcommandremovesoneargumentfromthelistof
17#commandlinearguments.
18shift
19shift
20#$*containsnowallthefiles:
21forfilein$*;do
22if[-f"$file"];then
23newfile=`echo"$file"|sed"s/${OLD}/${NEW}/g"`
24if[-f"$newfile"];then
25echo"ERROR:
$newfileexistsalready"
26else
27echo"renaming$fileto$newfile
"
28mv"$file""$newfile"
29fi
30fi
31done
我们从头来看,前面两行上一个例子中已经解释过了,从第三行开始,有新的内容。
if语句和其他编程语言相似,都是流程控制语句。
它的语法是:
if…;then
…
elif…;then
…
else
…
fi
与其他语言不同,ShellScript中if语句的条件部分要以分号来分隔。
第三行中的[]表示条件测试,常用的条件测试有下面几种:
[-f"$file"]判断$file是否是一个文件
[$a-lt3]判断$a的值是否小于3,同样-gt和-le分别表示大于或小于等于
[-x"$file"]判断$file是否存在且有可执行权限,同样-r测试文件可读性
[-n"$a"]判断变量$a是否有值,测试空串用-z
["$a"="$b"]判断$a和$b的取值是否相等
[cond1-acond2]判断cond1和cond2是否同时成立,-o表示cond1和cond2有一成立
要注意条件测试部分中的空格。
在方括号的两侧都有空格,在-f、-lt、=等符号两侧同样也有空格。
如果没有这些空格,Shell解释脚本的时候就会出错。
$#表示包括$0在内的命令行参数的个数。
在Shell中,脚本名称本身是$0,剩下的依次是$0、$1、$2…、${10}、${11},等等。
$*表示整个参数列表,不包括$0,也就是说不包括文件名的参数列表。
现在我们明白第三行的含义是如果脚本文件的参数少于三个,则执行if和fi语句之间的内容。
然后,从第四行到第十一行之间的内容在ShellScript编程中被称为Here文档,Here文档用于将多行文本传递给某一命令。
Here文档的格式是以<<开始,后跟一个字符串,在Here文档结束的时候,这个字符串同样也要出现,表示文档结束。
在本例中,Here文档被输出给cat命令,也即将文档内容打印在屏幕上,起到显示帮助信息的作用。
第十二行的exit是Linux的命令,表示退出当前进程。
在Shell脚本中可以使用所有的Linux命令,利用上面的cat和exit,从一方面来说,熟练使用Linux命令也可以大大减少Shell脚本的长度。
十四、十五两句是赋值语句,分别将第一和第二参数赋值给变量OLD和NEW。
紧接下来的两句是注释,注释下面的两条shift的作用是将参数列表中的第一个和第二个参数删除,后面的参数依次变为新的第一和第二参数,注意参数列表原本也不包括$0。
然后,自二十一行到三十一行是一个循环语句。
ShellScript中的循环有下面几种格式:
while[cond1]&&{||}[cond2]…;do
…
done
forvarin…;do
…
done
for((cond1;cond2;cond3))do
…
done
until[cond1]&&{||}[cond2]…;do
…
done
在上面这些循环中,也可以使用类似C语言中的break和continue语句中断当前的循环操作。
第二十一行的循环是将参数列表中的参数一个一个地放入变量file中。
然后进入循环,判断file是否为一个文件,如果是文件的话,则用sed命令搜索和生成新的文件名。
sed基本上可以看成一个查找替换程序,从标准输入,例如管道读入文本,并将结果输出到标准输出,sed使用正则表达式进行搜索。
在第二十三行中,backtick(`)的作用是取出两个backtick之间的命令输出结果,在这里,也就是将结果取出赋给变量newfile。
此后,判断newfile是否已经存在,否则就把file改成newfile。
这样我们就明白这个脚本的作用了,ShellScript编写的其他脚本与此相似,只不过是语法和用法稍有不同而已。
通过这个例子我们明白了ShellScript的编写规则,但还有几件事情需要讲述一下。
第一个,除了if语句之外,ShellScript中也有类似C语言中多分支结构的case语句,它的语法是:
casevarin
pattern1)
…;;
pattern2)
…;;
*)
…;;
esac
我们再就下面一个例子,看看case语句的用法。
whilegetoptsvc:
OPTION
do
case$OPTIONin
c)COPIES=$OPTARG
ehco"$COPIES";;
v)echo"suyang";;
\?
)exit1;;
esac
done
上面的getopts类似于C语言提供的函数getopts,在ShellScript中,getopts经常和while语句联合起来使用。
getopts的语法如下:
getoptsoption_stringvariable
option_string中包含一串单字符选项,若getopts在命令行参数中发现了连字符,那么它会将连字符之后的字符与option_string进行比较,若匹配成功,则把变量variable的值设为该选项,若无匹配,则把变量的值设为?
。
有时候,选项还会带一个值,例如-c5等,这时要在option_string中该选项字母后面加上一个冒号,getopts发现冒号后,会读取该值,然后将该值放入特殊变量OPTARG中。
这个命令比较复杂,如有需要,读者可以详细参阅Shell编写的相关资料。
上面这个循环的作用就是依次取出脚本名称后面的选项,进行处理,如果输入了非法选项,则进入"?
指定的部分,退出脚本程序。
第二个,Bash提供了一种用于交互式应用的扩展select,用户可以从一组不同的值中进行选择。
其语法如下:
selectvarin…;do
break;
done
例如,下面这段程序的输出是:
#!
/bin/bash
echo"Yourchoice?
"
selectvarin"a""b""c";do
break
done
echo$var
----------------------------
Yourchoice?
1)a
2)b
3)c
第三,ShellScript中也可以使用自定义的函数,其语法形式如下:
functionname()
{
…
}
例如我们可以把上面第二个例子中第四到第十二行放入一个名为help函数体内,以后每次调用的时候直接写help即可。
函数中处理函数调用参数的方法是,直接用上面讲过的$1、$2来分别表示第一、第二个参数,用$*表示参数列表。
第四,我们也可以在Shell下调试ShellScript脚本,当然最简单的方法就是用echo输出查看变量取值了。
Bash也提供了真正的调试方法,就是执行脚本的时候用-x参数。
sh?
xfilename.sh
这会执行脚本并显示脚本中所有变量的取值,也可以使用参数-n,它并不执行脚本,只是返回所有的语法错误。
特别需要注意的是,连字符“-”仅在方括号内有效,表示字符范围,如在方括号外面就成为普通字符了。
而*和?
只在方括号外面是通配符,若出现在方括号之内,它们也失去通配符的能力,成为普通字符了。
例如,模式“-a[*?
]abc”中只有一对方括号是通配符,*和?
均为普通字符,因此,它匹配的字符串只能是-a*abc和-a?
abc。
最后说明一下使用通配符时需要注意的一些问题。
由于*、?
和[]对于shell来说具有比较特殊的意义,因此在正常的文件名中不应出现这些字符。
特别是在目录名中不要出现它们,否则Shell匹配起来可能会无穷的递归下去。
另外要注意的一点是:
如果目录中没有与指定的模式串相匹配的文件名,那么Shell将使用此模式串本身作为参数传给有关命令。
这可能就是命令中出现特殊字符的原因所在。
2.引号
在shell中引号分为三种:
单引号,双引号和反引号。
*单引号‘
由单引号括起来的字符都作为普通字符出现。
特殊字符用单引号括起来以后,也会失去原有意义,而只作为普通字符解释。
例如:
$string=’$PATH’
$echo$string
$PATH
$
可见$保持了其本身的含义,作为普通字符出现。
*双引号“
由双引号括起来的字符,除$、、’、和”这几个字符仍是特殊字符并保留其特殊功能外,其余字符仍作为普通字符对待。
对于$来说,就是用其后指定的变量的值来代替这个变量和$;对于而言,是转义字符,它告诉shell不要对其后面的那个字符进行特殊处理,只当作普通字符即可。
可以想见,在双引号中需要在前面加上的只有四个字符$,,’和”本身。
而对”号,若其前面没有加,则Shell会将它同前一个”号匹配。
例如,我们假定PATH的值为.:
/usr/bin:
/bin,输入如下命令:
$TestString=”$PATH\”$PATH”
$echo$TestString
.:
/usr/bin:
/bin”$PATH
$
读者可以自己试一下在第二个双引号之前不加会产生什么结果。
*反引号`
反引号(`)这个字符所对应的键一般位于键盘的左上角,不要将其同单引号(’)混淆。
反引号括起来的字符串被shell解释为命令行,在执行时,shell首先执行该命令行,并以它的标准输出结果取代整个反引号(包括两个反引号)部分。
例如:
$pwd
/home/xyz
$string=”currentdirectoryis`pwd`”
$echo$string
currentdirectouris/home/xyz
$
shell执行echo命令时,首先执行`pwd`中的命令pwd,并将输出结果/home/xyz取代`pwd`这部分,最后输出替换后的整个结果。
利用反引号的这种功能可以进行命令置换,即把反引号括起来的执行结果赋值给指定变量。
例如:
$today=`date`
$echoTodayis$today
TodayisMonApr1516:
20:
13CST1999
$
反引号还可以嵌套使用。
但需注意,嵌套使用时内层的反引号必须用反斜线()将其转义。
例如:
$abc=`echoThenumberofusersis`who|wc-l``
$echo$abc
Thenumberofusersis5
$
在反引号之间的命令行中也可以使用shell的特殊字符。
Shell为得到``中命令的结果,它实际上要去执行``中指定的命令。
执行时,命令中的特殊字符,如$,”,?
等又将具有特殊含义,并且``所包含的可以是任何一个合法的Shell命令,如:
$ls
notereadme.txtNoticeUnix.dir
$TestString=”`echo$HOME``ls[nN]*`”
$echo$TestString
/home/yxznoteNotice
$
其他情况,读者可自行试之。
1.注释符
在shell编程中经常要对某些正文行进行注释,以增加程序的可读性。
在Shell中以字符“#”开头的正文行表示注释行。
此外还有一些特殊字符如:
用于输入/输出重定向与管道的<、>、<<、>>和|;执行后台命令的&;命令执行操作符&&和||及表示命令组的{}将在下面各小节中加以介绍。
标准输入/输出和重定向
1.标准输入与输出
我们知道,执行一个shell命令行时通常会自动打开三个标准文件,即标准输入文件(stdin),通常对应终端的键盘;标准输出文件(stdout)和标准错误输出文件(stderr),这两个文件都对应终端的屏幕。
进程将从标准输入文件中得到输入数据,将正常输出数据输出到标准输出文件,而将错误信息送到标准错误文件中。
我们以cat命令为例,cat命令的功能是从命令行给出的文件中读取数据,并将这些数据直接送到标准输出。
若使用如下命令:
$catconfig
将会把文件config的内容依次显示到屏幕上。
但是,如果cat的命令行中没有参数,它就会从标准输入中读取数据,并将其送到标准输出。
例如:
$cat
Helloworld
Helloworld
Bye
Bye
$
用户输入的每一行都立刻被cat命令输出到屏幕上。
另一个例子,命令sort按行读入文件正文(当命令行中没有给出文件名时,表示从标准输入读入),将其排序,并将结果送到标准输出。
下面的例子是从标准输入读入一个采购单,并将其排序。
$sort
bananas
carrots
apples
apples
bananas
carrots
$
这时我们在屏幕上得到了已排序的采购单。
直接使用标准输入/输出文件存在以下问题:
输入数据从终端输入时,用户费了半天劲输入的数据只能用一次。
下次再想用这些数据时就得重新输入。
而且在终端上输入时,若输入有误修改起来不是很方便。
输出到终端屏幕上的信息只能看不能动。
我们无法对此输出作更多处理,如将输出作为另一命令的输入进行进一步的处理等。
为了解决上述问题,Linux系统为输入、输出的传送引入了另外两种机制,即输入/输出重定向和管道。
2.输入重定向
输入重定向是指把命令(或可执行程序)的标准输入重定向到指定的文件中。
也就是说,输入可以不来自键盘,而来自一个指定的文件。
所以说,输入重定向主要用于改变一个命令的输入源,特别是改变那些需要大量输入的输入源。
例如,命令wc统计指定文件包含的行数、单词数和字符数。
如果仅在命令行上键入:
$wc
wc将等待用户告诉它统计什么,这时shell就好象死了一样,从键盘键入的所有文本都出现在屏幕上,但并没有什么结果,直至按下<ctrl+d>,wc才将命令结果写在屏幕上。
如果给出一个文件名作为wc命令的参数,如下例所示,wc将返回该文件所包含的行数、单词数和字符数。
$wc/etc/passwd
2023726/etc/passwd
$
另一种把/etc/passwd文件内容传给wc命令的方法是重定向wc的输入。
输入重定向的一般形式为:
命令<文件名。
可以用下面的命令把wc命令的输入重定向为/etc/passwd文件:
$wc
2023726
$
另一种输入重定向称为here文档,它告诉shell当前命令的标准输入来自命令行。
here文档的重定向操作符使用<<。
它将一对分隔符(本例中用delim表示)之间的正文重定向输入给命令。
下例将一对分隔符delim之间的正文作为wc命令的输入,统计出正文的行数、单词数和字符数。
$wc<>thistextformsthecontent
>oftheheredocument,which
>continuesuntiltheendof
>textdelimter
>delim
41798
在<<操作符后面,任何字符都可以作为正文开始前的分隔符,本例中使用delim作为分隔符。
here文档的正文一直延续到遇见另一个分隔符为止。
第二个分隔符应出现在新行的开头。
这时here文档的正文(不包括开始和结束的分隔符)将重新定向送给命令wc作为它的标准输入。
由于大多数命令都以参数的形式在命令行上指定输入文件的文件名,所以输入重定向并不经常使用。
尽管如此,当要使用一个不接受文件名作为输入参数的命令,而需要的输入内容又存在一个文件里时,就能用输入重定向解决问题。
1.输出重定向
输出重定向是指把命令(或可执行程序)的标准输出或标准错误输出重新定向到指定文件中。
这样,该命令的输出就不显示在屏幕上,而是写入到指定文件中。
输出重定向比输入重定向更常用,很多情况下都可以使用这种功能。
例如,如果某个命令的输出很多,在屏幕上不能完全显示,那么将输出重定向到一个文件中,然后再用文本编辑器打开这个文件,就可以查看输出信息;如果想保存一个命令的输出,也可以使用这种方法。
还有,输出重定向可以用于把一个命令的输出当作另一个命令的输入(还有一种更简单的方法,就是使用管道,将在下面介绍)。
输出重定向的一般形式为:
命令>文件名。
例如:
$ls>directory.out
$catdirectory.out
ch1.docch2.docch3.docchimpconfigmail/test/
$
将ls命令的输出保存为一个名为directory.out的文件。
注:
如果>符号后边的文件已存在,那么这个文件将被重写。
为避免输出重定向中指定文件只能存放当前命令的输出重定向的内容,shell提供了输出重定向的一种追加手段。
输出追加重定向与输出重定向的功能非常相似,区别仅在于输出追加重定向的功能是把命令(或可执行程序)的输出结果追加到指定文件的最后,而该文件原有内容不被破坏。
如果要将一条命令的输出结果追加到指定文件的后面,可以使用追加重定向操作符>>。
形式为:
命令>>文件名。
例如:
$ls*.doc>>directory.out
$catdirectory.out
ch1.docch2.docch3.docchimpconfigmail/test/
ch1.docch2.docch3.doc
$
和程序的标准输出重定向一样,程序的错误输出也可以重新定向。
使用符号2>(或追加符号2>>)表示对错误输出设备重定向。
例如下面的