shell脚本基础

 

最近准备花点时间学习下shell脚本语言,一是考虑到对以后找工作有帮助,因为很多上班了同学还有去面试的同学都说有的公司还是比较看重写shell脚本这个技能的,二是自己的工作需要,可能要写一些简单的脚本,虽然刚学linux时看《鸟哥的私房菜》时学过点皮毛,但现在已经忘的差不多了,刚好借这个机会系统学习一下。先将基础知识复习了一下,为进一步深入学习做准备。

 

 

 

 

 Shell脚本第一行的#! 

当一个文件中开头的两个字符是#!时,内核会扫描该行其余的部分,看是否存在可用来执行程序的解释器的完整路径(中间如果出现任何空白符号都会略过),此外内核还会扫描是否有一个选项要传递给解释器,内核会以被指定的选项来引用解释器。

shell脚本中: #/bin/csh –f

 

Shell识别三种基本命令:内建命令,shell函数以及外部命令

 

1.  内建命令即为shell本身所执行的命令,如cd用来改变目录,read将来自用户或文件的输入数据传给shell变量。

2.  Shell函数是功能健全的一系列程序代码,以shell语言写成,它们可以像命令一样引用。

3.  外部命令是由shell的副本即新的进程做执行的命令,其基本过程为:

a.       建立一个新的进程,此进程为shell的一个副本。

b.       在新进程里,在PATH指定的命令中,寻找特定的命令,如果命令以/开头时(说明制定了绝对路径名),将略过查找步骤。

c.       在新的进程里,以所找到的新程序取代执行中的shell程序并执行。

d.       程序完成后,最初的shell会从终端读取下一条命令,或执行脚本里的下一条命令。

 

shell中的变量

 

变量就是为某个信息片段所取的名字,变量的赋值方式为:先学变量名称,紧接着=字符,最后是新值,中间完全没有任何空格。通过在变量名前加$可解引用变量,当赋值的内容包含空格时,应加上引号。

first=jack middle=doson last =junior  单行可进行多次赋值

fullname=”jack doson junior”       值中包含空格时使用引号

oldname=$fullname               此时赋值不需要加引号

 

使用echoprintf输出信息

 

echo的任务是产生输出,可用来提示用户,或是用来产生数据提供进一步处理,如提示用户输入等,echo会在输出结束后提供换行符。

printf命令模仿C程序库里的printf()库函数,可用于格式化输出信息。

 

基本的IO重定向

 

<: 改变标准输入:

program < file 可将program的标准输入修改为file

>: 改变标准输出

program > file 可将program的标准输出修改为file

>>: 附加到文件

program > file 可将program的标准输出附加到file的结尾处;

|: 建立管道

program1 | program2 可将program1的标准输出改为program2的标准输入;

 

特殊的文件: /dev/null

 

传送到/dev/null文件的数据会被系统丢掉,即当程序将数据写到此文件时,会认为它已成功完成写入数据的操作,但实际上什么事也没有做;从/dev/null读取数据则会立即返回文件结束符。

如当需要的是命令的退出状态,而非其输出,此功能会非常有用,例如测试某个文件是否包含某个模式(pattern):

if grep pattern myfile > /dev/null

then

         找到匹配模式

else

   找不到匹配模式

fi

 

基本命令查找

 

shell会沿着查找路径$PATH寻找基本命令,$PATH是一个以冒号分隔的目录列表,列表中的目录为指定的命令查找位置,所找到的命令可能是编译后的可执行文件,也可能是shell脚本。

$PATH里的空项目表示当前目录,空项目位于路径中间时,可用两个连续的冒号来表示,如果将冒号直接置于前端或尾端,可以分别表示最先或最后查找当前目录。

PATH=:/bin:/usr/bin   先查找当前目录

PATH=/bin:/usr/bin:   最后查找当前目录

PATH=/bin::/usr/bin   当前目录居中

当然在PATH中加入当前目录最好的方法还是直接使用点号,这样更具可读性。

 

shell脚本的参数

 

$0: shell脚本的名称

$#: 参数的总个数

$*: 代表所有的参数,扩展为”$0 $1 … $n”

$@: 扩展为”$0” “$1” … “$n”

$1~n: 代表第n个参数,当超过9时,应使用大括号,如${10}代表第10个参数。

 

简单的执行跟踪

 

为了能迅速定位错误位置,就是把执行跟踪功能打开,这会使得shell显示每个被执行到的命令,并在前面加上“+ (加号+空格)

 

如:

$ sh –x nusers 通过-x执行跟踪功能

 //也可以在脚本中通过set –x/set +x 动态开启或关闭该功能。

 + who      被跟踪的命令

+ wc –l

    7      实际的输出

 

 

查找与替换

 

主要内容包括unix shell的正则表达式,以及模式匹配工具grep,awk,流编辑器sed,剪切工具cut,连接工具join的基本使用。

 

exportreadonlyunsetenv管理变量

readonly可以使变量成为只读模式,从而禁止改变变量的值,可用于在shell中创建常量。

export用于修改或打印环境变量。环境是一个名称与值的简单列表,可供所有执行中的程序使用。新的进程会从其父进程继承环境,export则可以将新变量添加到环境中。

unset从当前shell删除变量与函数。

env为在命令行执行程序的环境提供更细致的控制。

如: readonly hours_per_day=24  seconds_per_hour=3600 days_per_week=7

     export PATH=$PATH:/usr/local/bin

     export –p    显示当前的环境

     unset hours_per_day  删除hours_per_day变量

          env –i name=value… command arguments 

忽略继承的环境,只使用命令行的环境执行command

 

参数展开

参数展开是shell提供变量值在程序中使用的过程。

默认情况下,未定义的变量会展开为null(空的)字符串。

: rm –rf  /$program  如果program未被定义,则会引发灾难。

 

展开运算符

1.  替换运算法

${varname:-word} 如果varname存在且非null,则返回其值,否则返回word;可用于当变量未定义则返回默认值的情况。

${varname:=word} 如果varname存在其非null,则返回它的值,否则设置varnameword,并返回其值;可用于当变量未设置则设置其为默认值的情况。

${varname:?message} 如果varname存在且非null,则返回它的值,否则显示varnamemessage,并退出当前的命令或脚本。可用于捕捉变量未设置引发的错误,message为提示消息。

${varname:+word} 如果varname存在且非null,则返回word,否则返回null;可用于测试变量的存在性。

 

2.  模式匹配运算符

path=/home/tolstoy/mem/long.file.name

${variable#pattern} 如果模式匹配与变量的开头处,则删除匹配的最短部分,并返回剩下的部分。如${path#/*/}返回tolstoy/mem/long.file.name

${variable##pattern}如果模式匹配与变量的开头处,则删除匹配的最长部分,并返回剩下的部分。如${path##/*/}返回long.file.name

${variable%pattern} 如果模式匹配于变量的结尾处,则伤处匹配的最短部分,并返回剩下的部分。如${path%.*}返回tolstoy/mem/long.file

${variable%%pattern} 如果模式匹配于变量的结尾处,则伤处匹配的最短部分,并返回剩下的部分。如${path%%.*}返回tolstoy/mem/long

 

特殊变量

目前进程的参数个数;

传递给当前进程的命令行参数,等同于”$1” “$2” …

*  传递给当前进程的命令行参数,等同于”$1 $2 …”

?  前一进程的退出状态

$  shell进程的进程编号

0         shell程序的名称

 最近一个后台命令的进程编号

HOME 当前用户根目录

IFS 内部的字段分隔器,一般设为空格,制表符或换行符

LANG 当前locale 的默认名称

PATH 命令的查找路径

PPID 父进程的进程编号

PWD 当前工作目录

PS1  主要的命令提示符字符串,默认为$

PS2  行继续的提示符,默认为>

PS4  set –x设置的执行跟踪的提示字符串

 

算术展开

shell的算术运算符与C语言里的差不多,优先级与结合性也相同。

shell将置于$((…))中的内容解释为数学运算。

如: echo $((3 && 4))  输出1

     echo $((3 * 100))  输出300

&&||均为快捷运算符,当测试表达式的值确定后就停止执行。

 

退出状态

每一条命令,不管是内置的,shell函数,还是外部的,当它退出时,都会返回一个小的整数值给引用它的程序,该值即代表程序的退出状态。通常0表示成功,即程序执行完成且未遭遇任何问题。

POSIX的结束状态

0         命令成功地退出

1-125  命令不成功第退出。特定的退出值的含义,是由单个单独的命令定义的。

126 命令找到了,但文件无法执行

127 命令找不到

>128 命令因收到信号而死亡

 

exit可用于从shell脚本返回一个退出状态给脚本的调用者

 

if-elif-else-fi语句用于判断

if 测试条件1

then 执行动作1  #可以是多条语句

elif 测试条件2

then 执行动作2  #可以是多条语句

……

elif 测试条件n

then 执行动作n  #可以是多条语句

 

else

执行动作 #可以是多条语句

fi

 

test命令

test expreesion 或者 [ expression ](两边有空格)

test string  [ string ] :  string不为null

test –b file 或 [ -b file ]:  file是块设备文件

详细的说明参见man test

 

case语句

case $varname in

pattern1)  pattern1匹配

         …  执行命令

;;

pattern2)  pattern2匹配

   …  执行命令

   ;;

*)        默认情况

         .. 执行命令

         ;;

esac

 

for循环

for循环用于重复整个对象列表,依次执行每一个独立对象的循环内容。

如:for var in a.xml b.xml c.xml

         do echo $var

         done

该循环输出每一个xml文件的名字,如果没有指定列表的内容,则shell循环遍历整个命令行参数。

如:for var in

do

               ****多每一个参数进行的处理

done

 

while, until循环,breakcontinue

while conditon                      until conditon         

do                                  do

         statements                               statements

done                                done

 

while循环:只要condition是成功退出或为真,while会继续循环;

until循环:只要conditon未成功结束或为假,until继续循环。

 

breakcontinue:类比C语言中的用法,breakcontinue命令都接受可选的数值参数,可分别用来指出要中断(break)或是继续(continue)多少个被包含的循环。如:

while condition1     外部循环

do    

         while condition2 内部循环

         do

                   break 2    跳出外部循环

         done

done

……               中断之后继续执行

 

 

 

 
posted @ 2013-04-19 14:06  ydzhang  阅读(229)  评论(0编辑  收藏  举报