shell编程笔记(基本部分)
1.变量
a.需要给变量赋值时,可以这么写:
b.要取用一个变量的值,只需在变量名前面加一个$ ( 注意: 给变量赋值的时候,不能在"="两边留空格 )
c.然后执行 chmod +x first 使其可执行,最后输入 ./文件名 执行该脚本。
#!/bin/bash # 对变量赋值: a="hello world" #等号两边均不能有空格存在 # 打印变量a的值: echo "A is:" $a
如果变量与字符串混合,则按此方法
num=2 echo "this is the ${num}nd"
需要注意shell的默认赋值是字符串赋值
var=1 var=$var+1 echo $var #结果为1+1,不是2
推荐采用以下方法
let "var+=1" #方法1
var="$[$var+1]" #方法2
((var++)) #方法3
var=$(($var+1)) #方法4 注:前2种方式在bash下有效,在sh下会出错。
2.if 语 句
if ....; then .... elif ....; then .... else .... fi
大多数情况下,可以使用测试命令来对条件进行测试,比如可以比较字符串、判断文件是否存在及是否可读等等……通常用" [ ] "来表示条件测试,注意这里的空格很重要,
要确保方括号前后的空格。
- [ -f "somefile" ] :判断是否是一个文件
- [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
- [ -n "$var" ] :判断$var变量是否有值
- [ "$a" = "$b" ] :判断$a和$b是否相等
- 例如:
#!/bin/bash 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进行比较以判断当前使用的shell是否为bash。
3.&& 和 || 操作符
#!/bin/bash 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表达式完成任何事情,但是使用与或操作符会更便利很多 。
4.case 语句
case ... in ...) do something here ;; esac
例如:制作一个smartzip脚本,该脚本可以自动解压bzip2, gzip和zip 类型的压缩文件
#!/bin/bash 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。
5.select 语句
select var in ... ; do break; done .... now $var can be used ....
例如:
#!/bin/bash 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
6.while/for 循环
while ...; do .... done
只要测试表达式条件为真,则while循环将一直运行。关键字"break"用来跳出循环,而关键字”continue”则可以跳过一个循环的余下部分,直接跳到下一次循环中。
for循环会查看一个字符串列表(字符串用空格分隔),并将其赋给一个变量:
for var in ....; do .... done
下面的示例会把A B C分别打印到屏幕上:
#!/bin/bash for var in A B C ; do echo "var is $var" done
下面是一个实用的脚本showrpm,其功能是打印一些RPM包的统计信息:
#!/bin/bash # 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和 webgrep.rpm。$*的意思是差不多的。但是只有一个字串。如果不加引号,带空格的参数会被截断。
7.Shell里的一些特殊符号
在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓的扩展是指程序会把通配符(比如*)替换成适当的文件名,把变量替换成变量值。我们可以使用引号来防止这种扩展,先来看一个例子,假设在当前目录下有两个jpg文件:mail.jpg和tux.jpg。
- 单引号字串中不能出现单引号(对单引号使用转义符后也不行)
#!/bin/bash echo *.jpg
运行结果为:
mail.jpg tux.jpg
引号(单引号和双引号)可以防止通配符*的扩展:
#!/bin/bash echo "*.jpg" echo '*.jpg'
其运行结果为:
*.jpg *.jpg
其中单引号更严格一些,它可以防止任何变量扩展;而双引号可以防止通配符扩展但允许变量扩展:
#!/bin/bash echo $SHELL echo "$SHELL" echo '$SHELL'
运行结果为:
/bin/bash /bin/bash $SHELL
此外还有一种防止这种扩展的方法,即使用转义字符——反斜杆:\:
echo \*.jpg echo \$SHELL
输出结果为:
*.jpg $SHELL
8.Here Document
当要将几行文字传递给一个命令时,用here document是一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果使用here document就不必用echo函数一行行输出。Here document以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here document打印帮助:
#!/bin/bash # we have less than 3 arguments. Print the help text: if [ $# -lt 3 ] ; then cat << HELP ren -- renames a number of files using sed regular expressions USAGE: ren 'regexp' 'replacement' files... EXAMPLE: rename all *.HTM files in *.html: ren 'HTM$' 'html' *.HTM HELP #这里HELP要顶格写,前面不能有空格或者TAB制表符。如果cat一行写成cat << -HELP,前边可以带TAB. exit 0 fi OLD="$1" NEW="$2" # The shift command removes one argument from the list of # command line arguments. shift shift # $@ contains now all the files: for file in "$@"; do if [ -f "$file" ] ; then newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` if [ -f "$newfile" ]; then echo "ERROR: $newfile exists already" else echo "renaming $file to $newfile ..." mv "$file" "$newfile" fi fi done
第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。如果输入参数等于或大于3个,我们就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了目的:得到了旧文件名和新文件名。然后使用 mv命令进行重命名。
9.Shell里的函数
functionname() { # inside the body $1 is the first argument given to the function # $2 the second ... body }
下面是一个名为xtitlebar的脚本,它可以改变终端窗口的名称。这里使用了一个名为help的函数,该函数在脚本中使用了两次:
#!/bin/bash
help()
{
cat << HELP
xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
USAGE: xtitlebar [-h] "string_for_titelbar"
OPTIONS: -h help text
EXAMPLE: xtitlebar "cvs"
HELP
exit 0
}
# in case of error or if -h is given we call the function help:
[ -z "$1" ] && help #判断 $1 这个变量是不是空字符串 如果是,则返回真
[ "$1" = "-h" ] && help
# send the escape sequence to change the xterm titelbar:
echo -e "\033]0;$1\007"
#
在脚本中提供帮助是一种很好的编程习惯,可以方便其他用户(和自己)使用和理解脚本。
字符串操作
拼接字符串
your_name="qinjx"
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting $greeting_1
获取字符串长度:
string="abcd"
echo ${#string} #输出:4
提取子字符串
string="alibaba is a great company"
echo ${string:1:4} #输出:liba
查找子字符串
string="alibaba is a great company" echo `expr index "$string" is`#输出:8,这个语句的意思是:找出单词is在这名话中的位置
可以使用source和.关键字,如:
source ./function.sh
. ./function.sh
在bash里,source和.是等效的,他们都是读入function.sh的内容并执行其内容(类似PHP里的include),为了更好的可移植性,推荐使用第二种写法。
包含一个文件和在执行一个文件一样,也要写这个文件的路径,不能光写文件名,比如上述例子中:
. ./function.sh
不可以写作:
. function.sh
如果function.sh是用户传入的参数,如何获得它的绝对路径呢?方法是:
real_path=`readlink -f $1`#$1是用户输入的参数,如function.sh
. $real_path