首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Shell编程基础 part 一/2

2013-11-09 
Shell编程基础 part 1/2SHELL编程基础shell脚本, 必须在开始的第一行输入:1#!/bin/bash#! 会告诉系统执行

Shell编程基础 part 1/2

SHELL编程基础

shell脚本, 必须在开始的第一行输入:

1#!/bin/bash

>#! 会告诉系统执行该脚本的程序, 例如bash;

Note 最好使用"!/bin/bash"而不是"!/bin/sh", 如果使用tc shell改为tcsh,其他类似.

保存文件后, 想要执行脚本, 必须先使它可执行:

1chmod +x filename

>输入 ./filename就可以执行


1 变量赋值和引用

变量无需事先声明, 变量的命名规则:
1) 首字符必须为字母(a-z, A-Z)或者下划线_; 2) 中间不能有空格, 可以有下划线; 3) 不能使用其他标点符号;

赋值表达式: 变量名=值; [没空格]

取得变量的值, 需要在变量前加'$'

12345#!/bin/bash# 对变量赋值:a="hello world"  #等号两边均不能有空格存在# 打印变量a的值:echo "A is:" $a

>取得变量的值, 前面加 $;

Note 注意空格; 给变量赋值, 等号两边不能有空格;

区分文字和变量:

12num=2echo "this is the ${num}nd"

>输出: 'this is the 2nd'num 

>不加花括号的话, shell会搜索 '&numnd' 变量, 发现没有值; 输出: 'this is the '

注意花括号的位置:

12num=2echo "this is the {$num}nd"

>输出: 'this is the {2}nd'

Note shell的默认赋值是字符串赋值;

123var=1var=$var+1echo $var

>输出不是2而是 1+1;

为了达到数字效果:

123456let "var+=1"var="$[$var+1]"((var++))var=$(($var+1))var="$(expr "$var" + 1)" #不建议使用var="`expr "$var" + 1`" #强烈不建议使用,注意加号两边的空格,否则还是按照字符串的方式赋值,`为Esc下方的`,而不是单引号'。

Note 前2种方式在bash下有效, 在sh下会出错;

>let表示数学运算, expr用于整数值运算, 每一项用空格分开, $[]将中括号内的表达式作为数学运算先计算结果再输出;

shell脚本有许多便利是系统自动设定的, 除了只在脚本内有效的普通shell便另外, 还有环境变量, 即由export关键字处理过的变量, 一般只在登录脚本中用到;


2 Shell里的流程控制

if语句

if 表达式为真, 则执行 then 后的部分

1234567if ....; then  ....elif ....; then  ....else  ....fi

多数情况下, 可以使用测试命令来对条件进行测试, 比如可以比较字符串, 判断文件是否存在以及是否可读等等...通常用" [ ] "来表示条件测试; 

Note 要注意中括号前后的空格, 确保存在;

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

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

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

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

Note 执行 man test 可以查看所有测试表的式可以比较和判断的类型; 

e.g.

12345if [ ${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/hash比较来判断当前shell是否是bash;


&&和||操作符

类似C语言:

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

&&是一个快捷操作符, 如果左边的表达式为真则执行右边的语句, 可以看作逻辑运算中的与操作;

>如果/etc/shadow文件存在, 则打印文字; 

或操作 || 类似:

1234mailfolder=/var/spool/mail/james[ -r "$mailfolder" ] || { echo "Can not read $mailfolder" exit 1; }echo "$mailfolder has mail from:"grep "^From " $mailfolder

>先判断mailfolder是否可读, 可读则打印文件中的 From 行; [可读为true则不执行后面的条件]; 不可读则或操作生效, 打印错误信息, 脚本退出;

使用花括号以匿名函数的形式将两个命令放到一起作为一个命令, 以 ; 分割; 使用与, 或操作符会使脚本更便利;


case语句

case表达式可以用来匹配一个给定字符串, 而不是数字; (和C语言的switch...case不同)

1234case ... in   ...) do something here   ;;esac

file命令 可以辨别一个给定文件的文件类型; e.g. file lf.gz --> lf.gz: gzip compressed data, ...

利用file命令写smartzip脚本, 自动解压bzip2, gzip, zip不同类项的压缩文件:

12345678910ftype="$(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

Note 特殊变量$1, 包含传递给脚本的第一个参数值; e.g. 运行 smartzip sample.zip 时, $1就是字符串sample.zip; 


select语句

select表达式是bash的扩展应用, 用于交互式场合; 

1234select var in ... ; do break;done.... now $var can be used ....

e.g.

12345echo "What is your favourite OS?"select var in "Linux" "Gnu Hurd" "Free BSD" "Other"do  break;doneecho "You have selected $var"

>自动按照1)...2)...的方式输出选项;


while/for 循环

只要测试条件为真, while循环将一直运行; 关键字break跳出循环, continue跳过一个循环;

123while ...; do   ....done

for循环会查看字符串列表(字符串用空格分隔), 将其赋给一个变量:

123for var in ....; do   ....done

e.g.

123for var in A B C ; do   echo "var is $var"done

e.g. 脚本打印RPM包统计信息: showrpm   

1234567891011# list a content summary of a number of RPM packages# USAGE: showrpm rpmfile1 rpmfile2 ...# EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpmfor rpmpackage in "$@"do   if [ -r "$rpmpackage" ];then      echo "=============== $rpmpackage =============="      rpm -qi -p $rpmpackage   else      echo "ERROR: cannot read file $rpmpackage"   fidone

Note 特殊变量$@, 包含输入的所有命令行参数值; e.g. showrpm ssh.rpm web.rpm, 那么"$@"(必须有引号)就会出现2个字符串: ssh.rpm, web.rpm; 

$* 有类似功能, 但是只有一个字符串, 如果不加引号, 带空格的参数会被截断;


3 Shell里的特殊符号

引号

在向程序传递任何参数之前, 程序会扩展通配符和变量; 这里的扩展是指程序会把通配符(比如*)替换成适当的文件名, 变量替换成变量值; 使用引号可以防止这种扩展;

e.g. 假设目录下有两个jpg, mail.jpg和tux.jpg;

1echo *.jpg

>输出两个文件名;

单引号和双引号可以防止通配符的扩展:

12echo "*.jpg"echo '*.jpg'

>输出都是 *.jpg ;

单引号更严格, 可以防止任何变量扩展; 双引号则是防止通配符扩展但允许变量扩展:

123echo $SHELLecho "$SHELL"echo '$SHELL'

>输出 /bin/hash 和 /bin/bash 和 $SHELL;

还有一种防止扩展的方法, 使用转义字符--反斜杠 \ ;

12echo \*.jpgecho \$SHELL

>输出 *.jpg 和 $SHELL ;


4 Here Document

需要将几行文字传递给一个命令时, here document是不错的选择; 对每个脚本写一段帮助性的文字, 如果使用here document就不必用echo函数一行行输出; here document用 << 开头, 后面接一个字符串, 字符串必须出现在here document的末尾;

e.g. 对多个文件重命名, 使用here document打印帮助:

123456789101112131415161718192021222324252627282930# we have less than 3 arguments. Print the help text:if [ $# -lt 3 ] ; thencat << 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 0fiOLD="$1"NEW="$2"# The shift command removes one argument from the list of# command line arguments.shiftshift# $@ 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   fidone

>第一个if表达式判断输入命令行参数是否小于3个; 如果小于, 则将帮助文字传递给cat命令, 打印到屏幕上, 然后退出;

Note 特殊变量 $# 表示包含参数的个数; $2, $3 ...代表第二, 第三个参数; 

>如果输入参数>=3个, 将第一个参数赋值给变量OLD, 第二个赋值给变量NEW;  shift命令将第一个和第二个参数从参数列表删除, 原来的第三个参数变成参数列表$*的第一个参数;

>进入循环, 命令行参数列表被赋给$file, 判断文件是否存在, 存在则通过sed命令搜索和替换来产生新文件名; 然后将反斜线内命令结果赋值给newfile; 最后得到了旧文件名和新文件名, mv命令进行重命名;

[HELP不是关键字, 可以被其他字符替换(EOF), 加上单引号/双引号防止扩展] 

refer to http://www.serverwatch.com/columns/article.php/3860446/Shell-Scripts-and-Here-Documents.htm

12345cat <<- 'EOF'    test word    text will be printed    with out tabsEOF

热点排行