1. Linux 脚本编写基础 

1.1 语法基本介绍 

1.1.1 开头 

程序必须以下面的行开始(必须方在文件的第一行): 

#!/bin/sh 

符号#!用来告诉系统它后面的参数是用来执行该文件的程序。在这个例子中我们使用/bin/sh来执行程序。 

当编辑好脚本时,如果要执行该脚本,还必须使其可执行。 

要使脚本可执行: 

编译 chmod +x filename 这样才能用./filename 来运行 

1.1.2 注释 

在进行shell编程时,以#开头的句子表示注释,直到这一行的结束。我们真诚地建议您在程序中使用注释。如果您使用了注释,那么即使相当长的时间内没有使用该脚本,您也能在很短的时间内明白该脚本的作用及工作原理。 

1.1.3 变量 

在其他编程语言中您必须使用变量。在shell编程中,所有的变量都由字符串组成,并且您不需要对变量进行声明。要赋值给一个变量,您可以这样写: 

#!/bin/sh 

#对变量赋值:注意,等号两边不应有空格 

a="hello world" 

# 现在打印变量a的内容: 

echo "A is:" 

echo $a 

有时候变量名很容易与其他文字混淆,比如: 

num=2 

echo "this is the $numnd" 

这并不会打印出"this is the 2nd",而仅仅打印"this is the ",因为shell会去搜索变量numnd的值,但是这个变量时没有值的。可以使用花括号来告诉shell我们要打印的是num变量: 

num=2 

echo "this is the ${num}nd" 

#这将打印: this is the 2nd ,BASH 中变量定义是不需要的,没有 "int i" 这样的定义过程。如果想用一个变量,只要他没有在前面被定义过,就直接可以用,当然你使用该变量的第一条语句应该是对他赋初值了,如果你不赋初值也没关系,只不过该变量是空(注意:是 NULL,不是 0 )。大括号的作用,与双引号的区别:大括号,双引号使不能扩展,双引号不能阻止变量的扩展,只能阻止通配符*的扩展,后文有详细解释。 

关于变量的使用,要注意以下几点: 
一,变量赋值时,“=”左右两边都不能有空格; 
二,BASH 中的语句结尾不需要分号(";"); 
三,除了在变量赋值和在FOR循环语句头中,BASH 中的变量使用必须在变量前加"$"符号。 

在比较详细的 bash 文档中,会规定使用变量要采用这样的形式:${STR},如果你的脚本出了莫名其妙的错误,不妨看看是不是这个问题造成的。 

BASH 中的变量既然不需要定义,也就没有类型一说,那是不是一个变量既可以存放整数,也可以存放字符串呢?对! 
一个变量即可以被定义为一个字符串,也可以被再定义为整数。如果对该变量进行整数运算,他就被解释为整数;如果对他进行字符串操作,他就被看作为一个字符串。请看下面的例子: 

#!/bin/bash 
x=2006 
let "x = $x + 1" 
echo $x 
x="a string." 
echo $x 

执行一下看看?又出现了新的关键字:let。关于整数变量计算,有如下几种:" + - * / % ",他们的意思和字面意思相同,在*和/之前必须冠以反斜线,已防被SHELL先行解释。整数运算一般通过 let 和 expr 这两个指令来实现,如对变量 x 加 1 可以写作:let "x = $x + 1" 或者 x=`expr $x + 1` 

关于运行时参数,我们在执行脚本时有时很想传个参数进去,如:#sh mysh.sh hdz(回车)好,很简单,在 bash 中,使用这样传进来的变量时也要在前面加“$”符号。 

$# 传入脚本的命令行参数个数; 

$* 所有命令行参数值,在各个参数值之间留有空格; 

位置变元 

$0 命令本身(shell文件名) 

$1 第一个命令行参数; 

$2 第二个命令行参数; 

... 

好,编辑以下脚本: 
#!/bin/sh 

echo "number of vars:"$# 

echo "values of vars:"$* 

echo "value of var1:"$1 
echo "value of var2:"$2 
echo "value of var3:"$3 
echo "value of var4:"$4 

保存文件名为 my.sh,执行时传入参数:#sh my.sh a b c d e(回车),看到结果你就会更清楚各个变量的意思。如果访问的参数在执行时没有传入,如有一条这样的代码: 
echo "value of var4:"$100 

而在执行时并没有输入100个参数,那取得的值为 NULL 

在 BASH 程序中如果一个变量被使用了,那么直到该程序的结尾,该变量都一直有效。为了使得某个变量存在于一个局部程序块中,就引入了局部变量的概念。BASH 中,在变量首次被赋初值时加上 local 关键字就可以声明一个局部变量,如下面这个例子: 

#!/bin/bash 
HELLO="var1" 
echo $HELLO 
function hello { 
local HELLO="var2" 
echo $HELLO 


echo $HELLO 

该程序的执行结果是: 

var1 
var2 
var1 

这个执行结果表明全局变量 $HELLO 的值在执行函数 hello 时并没有被改变。也就是说局部变量 $HELLO 的影响只存在于函数那个程序块中。 

BASH 中的变量与 C 语言中变量的区别 
这里我们为原来不熟悉 BASH 编程,但是非常熟悉 C 语言的程序员总结一下在 BASH 环境中使用变量需要注意的问题。 

1,BASH 中的变量在引用时都需要在变量前加上 "$" 符号( 第一次赋值及在For循环的头部不用加 "$"符号 ); 
2,BASH 中没有浮点运算,因此也就没有浮点类型的变量可用; 
3,BASH 中的整形变量的比较符号与 C 语言中完全不同,而且整形变量的算术运算也需要经过 let 或 expr 语句来处理; 

1.1.4 环境变量 

由export关键字处理过的变量叫做环境变量。我们不对环境变量进行讨论,因为通常情况下仅仅在登录脚本中使用环境变量。 

1.1.5 Shell命令和流程控制 

在shell脚本中可以使用三类命令: 

1)Unix 命令: 

虽然在shell脚本中可以使用任意的unix命令,但是还是由一些相对更常用的命令。这些命令通常是用来进行文件和文字操作的。 

常用命令语法及功能 

echo "some text": 将文字内容打印在屏幕上 

ls: 文件列表 

wc –l file; wc -w file; wc -c file: 计算文件行数计算文件中的单词数计算文件中的字符数 

cp sourcefile destfile: 文件拷贝 

mv oldname newname : 重命名文件或移动文件 

rm file: 删除文件 

grep 'pattern' file: 在文件内搜索字符串比如:grep 'searchstring' file.txt 

cut -b colnum file: 指定欲显示的文件内容范围,并将它们输出到标准输出设备比如:输出.每行第5个到第9个字符cut -b5-9 file.txt千万不要和cat命令混淆,这是两个完全不同的命令 

cat file.txt: 输出文件内容到标准输出设备(屏幕)上 

file somefile: 得到文件类型 

read var: 提示用户输入,并将输入赋值给变量 

sort file.txt: 对file.txt文件中的行进行排序 

uniq: 删除文本文件中出现的行列比如: sort file.txt | uniq 

“|” 为管道描述符,详见后文。 

expr: 进行数学运算Example: add 2 and 3expr 2 "+" 3 

find: 搜索文件比如:根据文件名搜索find . -name filename -print 

tee: 将数据输出到标准输出设备(屏幕) 和文件比如:somecommand | tee outfile 

basename file: 返回不包含路径的文件名比如: basename /bin/tux将返回 tux 

dirname file: 返回文件所在路径比如:dirname /bin/tux将返回 /bin 

head file: 打印文本文件开头几行 

tail file : 打印文本文件末尾几行 

sed: Sed是一个基本的查找替换程序。可以从标准输入(比如命令管道)读入文本,并将结果输出到标准输出(屏幕)。该命令采用正则表达式(见参考)进行搜索。 

不要和shell中的通配符相混淆。比如:将linuxfocus 替换为 LinuxFocus : 

cat text.file | sed 's/linuxfocus/LinuxFocus/' > newtext.file 

awk: awk 用来从文本文件中提取字段。缺省地,字段分割符是空格,可以使用-F指定其他分割符。 

cat file.txt | awk -F, '{print $1 "," $3 }' 

这里我们使用,作为字段分割符,同时打印第一个和第三个字段。如果该文件内容如下: Adam Bor, 34, IndiaKerry Miller, 22, USA命令输出结果为:Adam Bor, IndiaKerry Miller, USA 

2) 概念: 管道, 重定向和 backtick 

这些不是系统命令,但是他们真的很重要。管道 (|) 将一个命令的输出作为另外一个命令的输入。 

grep "hello" file.txt | wc –l 

在file.txt中搜索包含有”hello”的行并计算其行数。 在这里grep命令的输出作为wc命令的输入。当然您可以使用多个命令。 

重定向:将命令的结果输出到文件,而不是标准输出(屏幕)。 

> 写入文件并覆盖旧文件 

>> 加到文件的尾部,保留旧文件内容。 

` ` 使用反短斜线可以将一个命令的输出作为另外一个命令的一个命令行参数。 

命令: 

find . -mtime -1 -type f -print 

用来查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。如果您想将所有查找到的文件打一个包,则可以使用以下脚本: 

#!/bin/sh 

# The ticks are backticks (`) not normal quotes ('): 

tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print` 

3) 流程控制 

1.if 

"if" 表达式 如果条件为真则执行then后面的部分: 

if ....; then 

.... 

elif ....; then 

.... 

else 

.... 

fi 

大多数情况下,可以使用测试命令来对条件进行测试。比如可以比较字符串、判断文件 

是否存在及是否可读等等… 

通常用" [ ] "来表示条件测试。注意这里的空格很重要。要确保方括号的空格。 

[ -f "somefile" ] :判断是否是一个文件 

[ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限 

[ -n "$var" ] :判断$var变量是否有值 

[ "$a" = "$b" ] :判断$a和$b是否相等 

BASH 是 Linux 操作系统的 Shell,因此系统的文件必然是 BASH 需要操作的重要对象 
运算符,下面说说对文件的操作: 含义( 满足下面要求时返回 TRUE ) 

-e 文件已经存在 
-f 文件是普通文件 
-s 文件大小不为零 
-d 文件是一个目录 
-r 文件对当前用户可以读取 
-w 文件对当前用户可以写入 
-x 文件对当前用户可以执行 
-g 文件的 GID 标志被设置 
-u 文件的 UID 标志被设置 
-O 文件是属于当前用户的 
-G 文件的组 ID 和当前用户相同 
file1 -nt file2 文件 file1 比 file2 更新 
file1 -ot file2 文件 file1 比 file2 更老 
如 if [ -x /root ] 可以用于判断 /root 目录是否可以被当前用户进入 
执行man test可以查看所有测试表达式可以比较和判断的类型。 

下面我们来看看变量之间的比较操作:在比较操作上,整数变量和字符串变量各不相同,详见下表: 

对应的操作 整数操作 字符串操作 
相同 -eq = 
不同 -ne != 
大于 -gt > 
小于 -lt < 
大于或等于 -ge 
小于或等于 -le 
为空 -z 
不为空 -n 
比如: 
比较整数 a 和 b 是否相等就写做 if [ $a = $b ] 
判断整数 a 是否大于整数 b 就写做 if [ $a -gt $b ] 
比较字符串 a 和 b 是否相等就写作:if [ $a = $b ] 
判断字符串 a 是否为空就写作: if [ -z $a ] 
判断整数变量 a 是否大于 b 就写作:if [ $a -gt $b ] 
注意:在“[”和“]”符号的左右都留有空格。 

直接执行以下脚本: 

#!/bin/sh 

If [ "$SHELL" = "/bin/bash" ]; then 

echo "your login shell is the bash (bourne again shell)" 

else 

echo "your login shell is not bash but $SHELL" 

fi 

变量$SHELL包含了登录shell的名称,我们和/bin/bash进行了比较。 

快捷操作符 

熟悉C语言的朋友可能会很喜欢下面的表达式: 

[ -f "/etc/shadow" ] && echo "This computer uses shadow passwors" 

这里 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句。 

您也可以认为是逻辑运算中的与操作。上例中表示如果/etc/shadow文件存在 

则打印” This computer uses shadow passwors”。同样或操作(||)在shell编程中也是 

可用的。这里有个例子: 

#!/bin/sh 

mailfolder=/var/spool/mail/james 

[ -r "$mailfolder" ] || { echo "Can not read $mailfolder" ; exit 1; } 

echo "$mailfolder has mail from:" 

grep "^From " $mailfolder 

该脚本首先判断mailfolder是否可读。如果可读则打印该文件中的"From" 一行。如果不可读则或操作生效,打印错误信息后脚本退出。这里有个问题,那就是我们必须有两个命令: 

-打印错误信息 

-退出程序 

我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用。一般函数将在下文提及。不用与和或操作符,我们也可以用if表达式作任何事情,但是使用与或操作符会更便利很多。 

2.case 

case :表达式可以用来匹配一个给定的字符串,而不是数字。 

case "$var" in 
condition1 ) 

condition2 ) 

* ) 
default statments;; 
esac 

下面这个程序是运用 case 结构进行分支执行的例子: 

#!/bin/bash 

echo "Hit a key, then hit return." 
read Keypress 

case "$Keypress" in 
[a-z] ) echo "Lowercase letter";; 
[A-Z] ) echo "Uppercase letter";; 
[0-9] ) echo "Digit";; 
* ) echo "Punctuation, whitespace, or other";; 
esac 

exit 0 

上面例子中的第四行 "read Keypress" 一句中的 read 语句表示从键盘上读取输入。这个命令将在本讲义的 BASH 的其他高级问题中讲解。 

break/continue 
熟悉 C 语言编程的都很熟悉 break 语句和 continue 语句。BASH 中同样有这两条语句,而且作用和用法也和 C 语言中相同,break 语句可以让程序流程从当前循环体中完全跳出,而 continue 语句可以跳过当次循环的剩余部分并直接进入下一次循环。 

让我们再看一个例子。 file命令可以辨别出一个给定文件的文件类型,比如: 

file lf.gz 

这将返回: 

lf.gz: gzip compressed data, deflated, original filename, 

last modified: Mon Aug 27 23:09:18 2001, os: Unix 

我们利用这一点写了一个叫做smartzip的脚本,该脚本可以自动解压bzip2, gzip 和zip 类型的压缩文件: 

#!/bin/sh 

ftype=`file "$1"` 

case "$ftype" in 

"$1: Zip archive"*) 

unzip "$1" ;; 

"$1: gzip compressed"*) 

gunzip "$1" ;; 

"$1: bzip2 compressed"*) 

bunzip2 "$1" ;; 

*) echo "File $1 can not be uncompressed with smartzip";; 

esac 

您可能注意到我们在这里使用了一个特殊的变量$1。该变量包含了传递给该程序的第一个参数值。也就是说,当我们运行: smartzip articles.zip 时 $1 就是字符串 articles.zip 

3. selsect 

select 表达式是一种bash的扩展应用,尤其擅长于交互式使用。用户可以从一组不同的值中进行选择。 

select var in ... ; do 

break 

done 

.... now $var can be used .... 

下面是一个例子: 

#!/bin/sh 

echo "What is your favourite OS?" 

select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do 

break 

done 

echo "You have selected $var" 

下面是该脚本运行的结果: 

What is your favourite OS? 

1) Linux 

2) Gnu Hurd 

3) Free BSD 

4) Other 

#? 1 

You have selected Linux 

4.loop 

loop表达式: 

while ...; do 

.... 

done 

while-loop 将运行直到表达式测试为真。will run while the expression that we test for is true. 关键字"break" 用来跳出循环。而关键字”continue”用来不执行余下的部分而直接跳到下一个循环。 

for-loop表达式查看一个字符串列表 (字符串用空格分隔) 然后将其赋给一个变量: 

for var in ....; do 

.... 

done 

在下面的例子中,将分别打印ABC到屏幕上: 

#!/bin/sh 

for var in A B C ; do 

echo "var is $var" 

done 

下面是一个更为有用的脚本showrpm,其功能是打印一些RPM包的统计信息: 

#!/bin/sh 

# list a content summary of a number of RPM packages 

# USAGE: showrpm rpmfile1 rpmfile2 ... 

# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm 

for rpmpackage in $*; do 

if [ -r "$rpmpackage" ];then 

echo "=============== $rpmpackage ==============" 

rpm -qi -p $rpmpackage 

else 

echo "ERROR: cannot read file $rpmpackage" 

fi 

done 

这里出现了第二个特殊的变量$*,该变量包含了所有输入的命令行参数值。如果您运行showrpm openssh.rpm w3m.rpm webgrep.rpm 此时 $* 包含了 3 个字符串,即openssh.rpm, w3m.rpm and webgrep.rpm. 

for 循环结构与 C 语言中有所不同,在 BASH 中 for 循环的基本结构是: 

for $var in [list] 
do 
#code block 
done 

其中 $var 是循环控制变量,[list] 是 var 需要遍历的一个集合,do/done 对包含了循环体,相当于 C 语言中的一对大括号。另外如果do 和 for 被写在同一行,必须在 do 前面加上 ";"。如: for $var in [list]; do 。下面是一个运用 for 进行循环的例子: 

#!/bin/bash 

for day in Sun Mon Tue Wed Thu Fri Sat 
do 
echo $day 
done 

# 如果列表被包含在一对双引号中,则被认为是一个元素 
for day in "Sun Mon Tue Wed Thu Fri Sat" 
do 
echo $day 
done 

exit 0 

注意上面的例子中,在 for 所在那行的变量 day 是没有加 "$" 符号的,而在循环体内,echo 所在行变量 $day 是必须加上 "$" 符号的。另外如果写成 for day 而没有后面的 in [list] 部分,则 day 将取遍命令行的所有参数。如这个程序: 

#!/bin/bash 

for param 
do 
echo $param 
done 

exit 0 

上面这个程序将列出所有命令行参数。for 循环结构的循环体被包含在 do/done 对中,这也是后面的 while、until 循环所具有的特点。 

while 循环的基本结构是: 

while [ condition ] 
do 
#code block 
done 

这个结构请大家自己编写一个例子来验证。 

until 循环的基本结构是: 

until [ condition is TRUE ] 
do 
#code block 
done 

这个结构也请大家自己编写一个例子来验证。 

5. 引号 

在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓扩展的意思是程序会把通配符(比如*)替换成合适的文件名,把变量替换成变量值。为了防 止程序作这种替换,您可以使用引号:让我们来看一个例子,假设在当前目录下有一些文件,两个jpg文件, mail.jpg 和tux.jpg。 

1.2 编译SHELL脚本 

#ch#!/bin/sh mod +x filename 

echo *.jpg 

done 

用./filename 来执行您的脚本。 这将打印出"mail.jpg tux.jpg"的结果。 引号 (单引号和双引号) 将防止这种通配符扩展: 

#!/bin/sh 

echo "*.jpg" 

echo '*.jpg' 

这将打印"*.jpg" 两次。 

单引号更严格一些。它可以防止任何变量扩展。双引号可以防止通配符扩展但允许变量扩展。 

#!/bin/sh 

echo $SHELL 

echo "$SHELL" 

echo '$SHELL' 

运行结果为: 

/bin/bash 

/bin/bash 

$SHELL 

最后,还有一种防止这种扩展的方法,那就是使用转义字符——反斜杆: 

Echo \ *.jpg 

echo \$SHELL 这将输出: 

*.jpg 

$SHELL 

6. Here documents 

当要将几行文字传递给一个命令时,here documents(译者注:目前还没有见到过对该词适合的翻译)是一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果我们四有那个 here documents 

就不必用echo函数一行行输出。 一个 "Here document" 以 shift by 2 

--) shift;break;; # end of options 

-*) echo "error: no such option $1. -h for help";exit 1;; 

*) break;; 

esac 

done 

echo "opt_f is $opt_f" 

echo "opt_l is $opt_l" 

echo "first arg is $1" 

echo "2nd arg is $2" 

您可以这样运行该脚本: 

cmdparser -l hello -f -- -somefile1 somefile2 

返回的结果是: 

opt_f is 1 

opt_l is hello 

first arg is -somefile1 

2nd arg is somefile2 

这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参数 

与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系统的惯例,首先输入的应该是包含减号的参数. 

第2部分 实例 

现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入参数。并且写一个伪脚本(framework.sh),该脚本包含了大多数脚本都需要的框架结构,是一个非常不错的主意。这时候,在写一个新的脚本时我们只需要执行一下copy命令: 

cp framework.sh myscript 

然后再插入自己的函数。 让我们再看两个例子: 

二进制到十进制的转换,脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命令进行数学运算的例子: 

#!/bin/sh 

# vim: set sw=4 ts=4 et: 

help() 



cat < 

b2h -- convert binary to decimal 

USAGE: b2h [-h] binarynum 

OPTIONS: -h help text 

EXAMPLE: b2h 111010 

will return 58 

HELP 

exit 0 



error() 



# print an error and exit 

echo "$1" 

exit 1 



lastchar() 



# return the last character of a string in $rval 

if [ -z "$1" ]; then 

# empty string 

rval="" 

return 

fi 

# wc puts some space behind the output this is why we need sed: 

numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` 

# now cut out the last char 

rval=`echo -n "$1" | cut -b $numofchar` 



chop() 



# remove the last character in string and return it in $rval 

if [ -z "$1" ]; then 

# empty string 

rval="" 

return 

fi 

# wc puts some space behind the output this is why we need sed: 

numofchar=`echo -n "$1" | wc -c | sed 's/ //g' ` 

if [ "$numofchar" = "1" ]; then 

# only one char in string 

rval="" 

return 

fi 

numofcharminus1=`expr $numofchar "-" 1` 

# now cut all but the last char: 

rval=`echo -n "$1" | cut -b 0-${numofcharminus1}` 



while [ -n "$1" ]; do 

case $1 in 

-h) help;shift 1;; # function help is called 

--) shift;break;; # end of options 

-*) error "error: no such option $1. -h for help";; 

*) break;; 

esac 

done 

# The main program 

sum=0 

weight=1 

# one arg must be given: 

[ -z "$1" ] && help 

binnum="$1" 

binnumorig="$1" 

while [ -n "$binnum" ]; do 

lastchar "$binnum" 

if [ "$rval" = "1" ]; then 

sum=`expr "$weight" "+" "$sum"` 

fi 

# remove the last position in $binnum 

chop "$binnum" 

binnum="$rval" 

weight=`expr "$weight" "*" 2` 

done 

echo "binary $binnumorig is decimal $sum" 

该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进制"10"可以这样转换成十进制: 0 * 1 + 1 * 2 = 2 为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字符。 

文件循环程序 

或许您是想将所有发出的邮件保存到一个文件中的人们中的一员,但是在过了几个月 

以后,这个文件可能会变得很大以至于使对该文件的访问速度变慢。下面的 脚本rotatefile 

可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为outmail)为outmail.1, 

而对于outmail.1就变成了outmail.2 等等等等... 

#!/bin/sh 

# vim: set sw=4 ts=4 et: 

ver="0.1" 

help() 



cat < 

rotatefile -- rotate the file name 

USAGE: rotatefile [-h] filename 

OPTIONS: -h help text 

EXAMPLE: rotatefile out 

This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1 

and create an empty out-file 

The max number is 10 

version $ver 

HELP 

exit 0 



error() 



echo "$1" 

exit 1 



while [ -n "$1" ]; do 

case $1 in 

-h) help;shift 1;; 

--) break;; 

-*) echo "error: no such option $1. -h for help";exit 1;; 

*) break;; 

esac 

done 

# input check: 

if [ -z "$1" ] ; then 

error "ERROR: you must specify a file, use -h for help" 

fi 

filen="$1" 

# rename any .1 , .2 etc file: 

for n in 9 8 7 6 5 4 3 2 1; do 

if [ -f "$filen.$n" ]; then 

p=`expr $n + 1` 

echo "mv $filen.$n $filen.$p" 

mv $filen.$n $filen.$p 

fi 

done 

# rename the original file: 

if [ -f "$filen" ]; then 

echo "mv $filen $filen.1" 

mv $filen $filen.1 

fi 

echo touch $filen 

touch $filen 

这个脚本是如何工作的呢?在检测用户提供了一个文件名以后,我们进行一个9到1的循环。文件9被命名为10,文件8重命名为9等等。循环完成之后,我们将原始文件命名为文件1同时建立一个与原始文件同名的空文件。 

调试 

最简单的调试命令当然是使用echo命令。您可以使用echo在任何怀疑出错的地方打印任何变量值。这也是绝大多数的shell程序员要花费80%的时间来调试程序的原因。Shell程序的好处在于不需要重新编译,插入一个echo命令也不需要多少时间。 

shell也有一个真实的调试模式。如果在脚本"strangescript" 中有错误,您可以这样来进行调试: 

sh -x strangescript 

这将执行该脚本并显示所有变量的值。 

shell还有一个不需要执行脚本只是检查语法的模式。可以这样使用: 

sh -n your_script 

这将返回所有语法错误。 

关于bash在控制台下的快捷键 

ctrl+u 删除光标以前的所有字符 
ctrl+d 删除光标以前的一个字符 
ctrl+k 删除光标以后的所有字符 
ctrl+h 删除光标以后的一个字符 
ctrl+t 调换光标前两个字符的次序 
ctrl+a 移动光标到最前面 
ctrl+e 移动光标到最后面 
ctrl+p 上一个命令 
ctrl+n 下一个命令 
ctrl+s 锁定输入 
ctrl+q 解除锁定 
ctrl+f 移动光标到后一个字符 
ctrl+b 移动光标到前一个字符 
ctrl+x 标记一个位置 
ctrl+c 清除当前的输入 

最基本的理论基础 
这里有对于三个文件的重定向定义:stdin(标准输入),stdout(标准输出)andstderr(标准错误输出)(std=standard). 
基本上你可以 
1.重定向stdout到一个文件 
2.重定向stderr到一个文件 
3.重定向stdout到stderr 
4.重定向stderr到stdout 
5.重定向stderr到stdout中并且成为一个文件 
6.重定向stderrandstdouttostdout 
7.重定向stderrandstdouttostderr 
在Linux中1代表标准输出,2代表'标准错误' 
标准输出 
这个例子将会使ls的显示结果重定向到一个文件中. 
ls-l>ls-l.txt 
标准错误 
这个例子将会使grep命令在运行过程中出现的错误输出到一个文件中 
grepda*2>grep-errors.txt 
管道 
这一节我们将解释一个非常简单的并且你以后一定会用到的功能,它就是管道。 
为什么大家都会用到管道? 
管道可以使你非常方便的将一个程序的结果转向到另外一个程序中。 
一个sed的例子 
这个例子使用了非常简单的管道功能: 
ls-l|sed-e"s/[aeio]/u/g" 
当我们执行以下命令后:首先ls–l会先执行并且它会输出结果信息但是如果它的后面跟是一个管道符的话,那么它就会将结果重新定向到sed这个程序中,sed使用了替换功能,所以这个例子执行完会,会将ls–l结果中所有含有aeio的英文单词替换成单词u. 
通过另外的方法实现ls–l*.txt 
也许这种方法不同于ls–l*.txt,但是它避免了出现一条NoSuchfileOrDirectory这种信息。 
ls-l|grep".txt" 
当ls–l执行后,它会将程序结果输出到grep这个程序中,并且去匹配.txt这条信息。

BASH 学习笔记小结的更多相关文章

  1. openresty 学习笔记小结:综合应用实例

    openresty 学习笔记小结:综合应用实例 这个综合实验实现的功能其实很简单,用户访问一个页面,显示一个默认页面.输入参数(post或者get都可以),如果参数在数据库查询得到并满足一定条件,根据 ...

  2. 初学c# -- 学习笔记 小结

    学了到了好些东西, 做了一些练习. 一.C# winform Socket 1.程序主要部分只是用了 Panel.Picturebox.Label.RicheditBox四个组件,滚动条.编辑框什么的 ...

  3. bash 学习笔记

    shell:能够操作应用程序的接口就称为shell. Linux由C编写的. TAB键的使用 alias:设置别名

  4. bash 学习笔记(一)

    尽量使用printf而不要用echo(echo再不同情况下语义不同) 整数%d,小数后6位%f,科学计数法 %e,16进制 %x 宽度限制 %8s %-15s 正数朝右对齐 负数朝左对齐:%04d\n ...

  5. [转帖][Bash Shell] Shell学习笔记

    [Bash Shell] Shell学习笔记 http://www.cnblogs.com/maybe2030/p/5022595.html  阅读目录 编译型语言 解释型语言 5.1 作为可执行程序 ...

  6. [原创]java WEB学习笔记42:带标签体的自定义标签,带父标签的自定义标签,el中自定义函数,自定义标签的小结

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  7. [原创]java WEB学习笔记11:HttpServlet(HttpServletRequest HttpServletRsponse) 以及关于 Servlet 小结

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  8. Bash脚本编程学习笔记08:函数

    官方资料:Shell Functions (Bash Reference Manual) 简介 正如我们在<Bash脚本编程学习笔记06:条件结构体>中最后所说的,我们应该把一些可能反复执 ...

  9. Bash脚本编程学习笔记07:循环结构体

    本篇中涉及到算术运算,使用了$[]这种我未在官方手册中见到的用法,但是确实可用的,在此前的博文<Bash脚本编程学习笔记03:算术运算>中我有说明不要使用,不过自己忘记了.大家还是尽量使用 ...

随机推荐

  1. html查看器android

    1.android的API提供了访问网络的一个类HttpURLConnection 2.通过发送GET请求获取服务器返回的html代码 3.先看看布局文件,如下所示, <?xml version ...

  2. HttpClient4.5 post请求xml到服务器

    1.加入HttpClient4.5和junit依赖包 <dependencies> <dependency> <groupId>org.apache.httpcom ...

  3. ArcGIS API for JavaScript 4.2学习笔记[28] 可视域分析【使用Geoprocessor类】

    想知道可视域分析是什么,就得知道可视域是什么 我们站在某个地方,原地不动转一圈能看到的所有事物就叫可视域.当然平地就没什么所谓的可视域. 如果在山区呢?可视范围就会被山体挡住了.这个分析对军事上有十分 ...

  4. GAME——转圈游戏

    我们在生命的路上常常绝望 大概是因为弯路走了太多 脚上的泡被磨起又磨破 像我们所有的幻想与梦 起起落落. 所以说 我这道题考场上面和题解想得一模一样啊啊啊啊啊啊啊啊啊啊!!!!!! 但是就是打复杂了啊 ...

  5. 跟我一起读postgresql源码(七)——Executor(查询执行模块之——数据定义语句的执行)

    1.数据定义语句的执行 数据定义语句(也就是之前我提到的非可优化语句)是一类用于定义数据模式.函数等的功能性语句.不同于元组增删査改的操作,其处理方式是为每一种类型的描述语句调用相应的处理函数. 数据 ...

  6. RBAC__权限设计__结构化表的输出(不知道怎么描述标题,反正就是设计表) 难点重点 必须掌握🤖

    RBAC 反正就是很厉害. 干就完事了,不BB 直接进入正题 本文写的就是如何设计表,以及设计表的思路. 用户和角色 : 多对多字段放在哪张表更好点? 用户找角色,角色找权限. 放在user表中,是正 ...

  7. ASP.NET MVC 5使用Swagger生成API文档

    一.安装 新建一个没有身份验证的mvc项目 - SwaggerMvc5Demo,然后添加一个名为Remote(自定义)且包含基础读写(不想手写)的ApiController   开源地址:https: ...

  8. VBox 一款基于vue开发的音乐盒 序章

    己基于vue写了一个 Mplayer, github地址:https://github.com/xiangwenhu/MPlaer, 演示地址:http://babydairy2017.cloudap ...

  9. 使用Python实现的杨辉三角

    def triangel(): print ' '*(20*3)+str(1) #定义起始两行 print ' '*(19*3)+str(1)+' '*5+str(1) for i in range( ...

  10. 一个InnoDB性能超过Oracle的调优Case

    年前抽空到兄弟公司支援了一下Oracle迁移MySQL的测试,本想把MySQL调优到接近Oracle的性能即可,但经过 @何_登成 @淘宝丁奇 @淘宝褚霸 @淘伯松 诸位大牛的指导和帮助(排名不分先后 ...