shell程序设计笔记
2014-08-02 11:07
274 查看
1 shell是什么
shell是一个作为用户与Linux系统间接口的程序,它允许用户向操作系统输入需要执行的命令。
2 shell的种类
3 shell同类技术及优缺点对比
可参考博客:对python与shell的一些思考
4 shell语法
4.1 shell脚本运行
1> 交互式程序
交互式即是在命令行上直接输入shell脚本。
当shell期待进一步的输入时,正常的$提示符将改变为>提示符。你可以一直输入下去,由shell来判断何时输入完毕并立刻执行脚本程序。
2> 创建脚本
编辑包含命令的脚本文件first.sh
程序中的注释以#开始,一直持续到该行的结束。
第一行#!/bin/sh的#!是一种特殊形式的注释,其告诉系统同一行上紧跟其后面的参数是用来执行本文件的程序。
编辑
Linux环境下可用vi或vim等编辑器。
Windows环境下可用notepad++、gvim等编辑器,当mount到linux虚拟机上运行时,需要转换下脚本的文件格式,
使用命令:dos2unix filename
运行
3> 后台模式运行脚本
当脚本在运行时,你没法在终端会话里做别的事情。而利用ps命令查看,有一系列不同进程运行在linux上。显然这些进程都不是运行在你的终端上的。这些进程我们称为后台运行进程。在后台模式中,进程运行时不会和终端会话上的STDIN、STDOUT以及STDERR关联。要让脚本在命令行界面以后台模式运行,只要在命令后加个&符就行。如:
$ ./1.sh &
4.2 变量
shell的变量类型主要分为三种:1>用户变量2>环境变量3>特殊变量
4.2.1 用户变量
Shell脚本允许用户根据需要在脚本中定义和使用自己的变量。
.局部变量
要让一个变量成为某函数里的局部变量,只需在变量前加关键字local即可。如此,局部变量仅在函数的作用范围内有效。
例如: foo() {local var=123 …}函数中var为局部变量。
.只读变量
要让一个变量成为只读变量,只需要在变量前加上关键字readonly即可。只读变量一旦定义就不可更改其值,也不能用unset删除。
例如:readonly var=123 或
var=123
readonly var
.数组变量
定义数组
格式:array_name=(value0value1 value2 value3 …)或者
array_name=(
value0
value1
value2
…
)
或者
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
……
注意:各元素之间用空格隔开,数组下标从0开始。
.导出变量
通过export命令,可将作为它参数的变量导出到子shell中,并使之在子shell中有效。
4.2.2 环境变量
Linux是一个多用户的操作系统。多用户意味着每个用户登录系统后,都有自己专用的运行环境。而这个环境是由一组变量所定义,这组变量被称为环境变量。用户可以对自己的环境变量进行修改以达到对环境的要求。
Shell用环境变量来获取系统信息、存储有关shell会话和工作环境的信息和配置信息。环境变量也可用来存储永久数据,这些数据可以是用来识别用户账户、系统、shell的特性以及任何其他需要存储的数据。
Bash shell中,环境变量分为两类:1全局变量 2局部变量
全局环境变量不仅对shell会话可见,对所有shell创建的子进程也可见。可使用env命令查看。
局部环境变量则只对创建它们的shell可见。可使用set命令查看。
4.2.3 特殊变量
Shell特殊内置变量通常也被称为参数变量,主要被shell脚本用来从命令行接收参数、或者被函数用来保存传给它的参数。
4.2.4 管道重定向引号反引号及其他
4.3 条件语句
test命令可以使用的条件类型可以归为3类:1>字符串比较2>算术比较3>文件有关的条件测试
复合条件
方式1:
与:
if [ 条件1 ] && [ 条件2 ] && [ 条件3 ]; then ... fi
说明:先判断条件1是否为真,当条件1不为真时,直接退出;当条件1为真时,再去判断条件2是否为真。
或:
if [ 条件1 ] || [ 条件2 ] || [ 条件3 ]; then ... fi
非:
if [ ! 条件 ]; then ... fi
方式2:
与: if [ 条件1 -a 条件2 ]; then ... fi
说明:同时判断条件1和条件2是否为真。
或: if [ 条件1 -o 条件2 ]; then ... fi
非: if [ !条件 ]; then ... fi
4.4 循环语句
示例:grep -E "2010-01-01|hello" filename #在文件filename中搜索2010-01-01和hello的行
4.5 命令
Shell程序内部可执行两类命令:
<1>外部命令,即可以在命令提示符中执行的普通命令。
<2>内部命令,即在shell内部实现的内置命令。
4.5.1 break命令
break命令在控制条件未满足之前,跳出for、while或until循环。默认情况下,break只跳出一层循环。也可为break提供数值参数来表明需要跳出的循环层数,但不建议这么做。
4.5.2 continue命令
continue命令使for、while或until循环跳到下一次循环继续执行,循环变量取循环列表中的下一个值。也可为continue提供数值参数来表明需要跳过几次循环。
4.5.3 :命令
冒号(:)命令是一个空命令。
作用1>简化条件逻辑。
作用2>true的别名
while : 实现了一个无限循环,代替更常见的while true。
作用3>:${var:=value} #说明:当var为未赋值或为空时,将value的值赋给var。若没有前面的冒号:,则${var:=value}会报错。
4.5.4 .命令
通常,当一个脚本执行一条外部命令或脚本程序时,它会创建一个新的环境(一个子shell),命令将在这个心环境中执行,在命令执行完毕后,这个环境被丢弃,留下退出码返回给父shell。
外部的source命令和点(.)命令在执行脚本程序中列出的命令时,使用的是调用该脚本程序的同一个shell。
4.5.5 echo命令
echo命令用来输出结尾带有换行符的字符串。
去掉换行符的方法:
1>echo –n “stringto output”
2>printf “stringto output”
4.5.6 eval命令
eval命令用来对参数进行求值。
4.5.7 exec命令
exec的典型用法是将当前shell替换为一个不同的程序。
exec wall "Thanksfor all the fish"
该命令会用wall命令替换当前的shell。脚本程序中exec命令后面的代码都不会执行,因为执行这个脚本的shell已经不存在。
4.5.8 exit n命令
exit命令使脚本程序以退出码n结束运行。
如果脚本程序在退出时不指定一个退出状态,那该脚本中最后一条被执行命令的状态将被用作为返回值。
4.5.9 export命令
export将作为它参数的变量导出到子shell中,并使之在子shell中有效。
在默认情况下,在一个shell中被创建的变量在这个shell调用的子shell中是不可用的。export命令把自己的参数创建为一个环境变量,而这个环境变量可以被当前程序调用的其他脚本和程序看见。
$ export1.sh
4.5.10 expr命令
expr命令将它的参数当作一个表达式来求值。
x=$(expr $x+1)
expr命令可以完成许多表达式求值计算。
4.5.11 printf命令
最新版本的shell才提供printf命令,以产生格式化的输出。
语法:printf "formatstring" parameter1 parameter2 …
4.5.12 return命令
return命令的作用是使函数返回。
return命令有一个数值参数,这个参数在调用该函数的脚本程序里被看做是该函数的返回值。如果没有指定参数,return命令默认返回最后一条命令的退出码。
4.5.13 set命令
set命令的作用是为shell设置参数变量。许多命令的输出结果是以空格分隔的值,如果需要使用输出结果中的某个域,这个命令就非常有用。
4.5.14 shift命令
shift命令把所有参数变量左移一个位置,使$2变成$1,$3变成$2,以此类推。原来$1的值将被丢弃,而$0扔保持不变。
如果调用shift命令时指定了一个数值参数,则表示所有的参数将左移指定的次数。
trap命令用于指定在接收到信号后将要采取的行动。trap命令的一种常见用途是在脚本程序被中断时完成清理工作。
trap -l命令用来查看信号编号及其关联的名称:
trap的语法:trap commandsignal
第一个参数command是接收到指定信号时将要采取的动作。
第二个参数signal是要处理的信号名。
脚本程序通常是以上从到下的顺序解释执行的,所以你必须在你想保护的那部分代码之前指定trap命令。
重置某个信号的处理方式到期默认值,只需将command设置为-
要忽略某个信号,只需把command设置为空字符串''
unset命令的作用是从环境中删除变量或函数。这个命令不能删除shell本身定义的只读变量(如IFS)
find是用于搜索文件的命令。
语法:find [path][options] [tests] [actions]
可用操作符来组合测试。大多数操作符有两种格式:短格式和长格式。
4.5.18 grep命令
grep即GeneralRegular Expression Parser(通用正则表达式解析器)的简写。使用find命令在系统中搜索文件,而使用grep命令在文件中搜索字符串。常见的用法是在使用find命令时,将grep作为传递给-exec的一条命令。
grep命令使用一个选项、一个要匹配的模式和要搜索的文件。如果没有提供文件名,则grep搜索标准输入。
语法:grep [options] PATTERN [FILES]
4.6 函数
参数:
当一个函数被调用时,脚本程序的位置参数($*、$@、$#、$1、$2等)会被替换为函数的参数。
返回值:
函数返回数字值——return命令。
函数返回字符串值——让函数将字符串保存在一个变量中,该变量可以在函数结束之后被使用。
局部变量
函数中声明局部变量——local关键字
4.7 调用另一个脚本
shell调用另一个shell脚本有三种方法:
1>fork (格式: /directory/script.sh)
fork是最普通的, 就是直接在脚本里面用/directory/script.sh来调用script.sh这个脚本.
运行的时候开一个sub-shell执行调用的脚本,sub-shell执行的时候, parent-shell还在。
sub-shell执行完毕后返回parent-shell. sub-shell从parent-shell继承环境变量.但是sub-shell中的环境变量不会带回parent-shell
2>exec (格式:exec /directory/script.sh)
exec与fork不同,不需要新开一个sub-shell来执行被调用的脚本. 被调用的脚本与父脚本在同一个shell内执行。但是使用exec调用一个新脚本以后, 父脚本中exec行之后的内容就不会再执行了。这是exec和source的区别。
3>source (格式:source /directory/script.sh)
与fork的区别是不新开一个sub-shell来执行被调用的脚本,而是在同一个shell中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中得到和使用.
5 shell调试
跟踪脚本程序中复杂错误的主要方法是设置各种shell选项。如,可以在调用shell时加上命令行选项,或是使用set命令。
6 shell应用
Linux所有的任务都可以通过命令行来完成,而这可以通过shell来实现。
shell可以将简单的任务自动化。
shell强调易于配置、易于维护和可移植性,所以它适合编写一些执行相对简单的任务的小工具。又因为是解释执行的,所以不适合用来完成时间紧迫型和处理器忙碌型的任务。
shell是一个作为用户与Linux系统间接口的程序,它允许用户向操作系统输入需要执行的命令。
2 shell的种类
UNIX系统常见的shell | ||
名称 | 路径 | 相关历史 |
Bourne shell | /bin/sh | 源于UNIX早期版本的最初shell |
Bourne-again shell | /bin/bash | GNU shell,所有Linux系统都提供。遵循POSIX且与Bourne shell兼容,可免费获取其源代码。 |
C shell | /bin/csh | 由Bill Joy在Berkeley UNIX上开发,所有BSD版本都提供这种shell。其控制流类似于C语言。 |
Korn shell | /bin/ksh | 由David Korn在贝尔实验室开发,是Bourne shell的后继者。 |
可参考博客:对python与shell的一些思考
4 shell语法
4.1 shell脚本运行
1> 交互式程序
交互式即是在命令行上直接输入shell脚本。
<span style="font-size:14px;">$ for file in * > do > if grep -l bin $file > then > more $file > fi > done 1.sh </span>
当shell期待进一步的输入时,正常的$提示符将改变为>提示符。你可以一直输入下去,由shell来判断何时输入完毕并立刻执行脚本程序。
2> 创建脚本
编辑包含命令的脚本文件first.sh
<span style="font-size:14px;">#!/bin/sh #this file is first.sh for file in * do if grep –l bin $file then echo $file fi done exit 0 </span>
程序中的注释以#开始,一直持续到该行的结束。
第一行#!/bin/sh的#!是一种特殊形式的注释,其告诉系统同一行上紧跟其后面的参数是用来执行本文件的程序。
编辑
Linux环境下可用vi或vim等编辑器。
Windows环境下可用notepad++、gvim等编辑器,当mount到linux虚拟机上运行时,需要转换下脚本的文件格式,
使用命令:dos2unix filename
运行
<span style="font-size:14px;">$ /bin/sh filename 或 $ chmod 755 filename $ ./filename </span>
3> 后台模式运行脚本
当脚本在运行时,你没法在终端会话里做别的事情。而利用ps命令查看,有一系列不同进程运行在linux上。显然这些进程都不是运行在你的终端上的。这些进程我们称为后台运行进程。在后台模式中,进程运行时不会和终端会话上的STDIN、STDOUT以及STDERR关联。要让脚本在命令行界面以后台模式运行,只要在命令后加个&符就行。如:
$ ./1.sh &
4.2 变量
shell的变量类型主要分为三种:1>用户变量2>环境变量3>特殊变量
4.2.1 用户变量
Shell脚本允许用户根据需要在脚本中定义和使用自己的变量。
命名 | 变量名由不超过20个字母、数字或下划线组成,不以数字开头且区分大小写 |
赋值 | 直接赋值格式:变量名=值(注:变量名等号和值之间不能出现空格) 交互赋值格式:read变量名(注:变量在使用之前不需要事先声明) |
取值 | $变量名 |
作用域 | 仅限于当前shell脚本中使用,其他的shell脚本不能使用 |
生命周期 | 在当前shell脚本的整个生命周期里一直存在,直到shell脚本完成时删除掉 |
要让一个变量成为某函数里的局部变量,只需在变量前加关键字local即可。如此,局部变量仅在函数的作用范围内有效。
例如: foo() {local var=123 …}函数中var为局部变量。
.只读变量
要让一个变量成为只读变量,只需要在变量前加上关键字readonly即可。只读变量一旦定义就不可更改其值,也不能用unset删除。
例如:readonly var=123 或
var=123
readonly var
.数组变量
定义数组
格式:array_name=(value0value1 value2 value3 …)或者
array_name=(
value0
value1
value2
…
)
或者
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2
……
注意:各元素之间用空格隔开,数组下标从0开始。
数组取值 | |
${array_name[index]} | 获取下标为index的数组值 |
${array_name[*]} | 获取整个数组的值 |
${#array_name[*]} | 获取数组元素个数 |
${array_name[@]} | 获取整个数组的值,可以处理包含空格的数组元素 |
数组部分取值 array_name=(10 11 12 13 14 15} | |
${array_name[*]:0} | 结果为所有元素:10 11 12 13 14 15 |
${array_name[*]:1} | 结果为第一个元素除外,其他所有元素:11 12 13 14 15 |
${array_name[*]:0:2} | 结果为:10 11 |
${array_name[*]:0:4} | 结果为:10 11 12 13 |
${array_name[*]:1:2} | 结果为:11 12 |
${array_name[*]:1:4} | 结果为:11 12 13 14 |
${array_name[*]:2:4} | 结果为:12 13 14 |
子串删除 array_name=([0]=one [1]=two [2]=three [3]=four} | |
${array_name[*]#t*e} | 左边开始最短的匹配:”t*e”。结果匹配到thre |
${array_name[*]##t*e} | 左边开始最长的匹配:”t*e”。结果匹配到three |
${array_name[*]%o} | 从字符串的结尾开始最短匹配:o。结果[1]为tw |
${array_name[*]%%o} | 从字符串的结尾开始最长匹配:o。结果为[1]为tw |
子串替换 array_name=([0]=one [1]=two [2]=three [3]=four} | |
${array_name[*] /o/m} | 第一个匹配到字符o的会被替换为字符m |
${array_name[*] //o/m} | 所有匹配到字符o的都会被替换为字符m |
${array_name[*] //o/} | 没有指明替换字符串,则删除匹配到的字符o |
${array_name[*] /#o/k} | 替换字符串前端子串。结果:kne two three four |
${array_name[*] /%o/k} | 替换字符串后端子串。结果:one twk three four |
删除数组 | |
unset array_name[1] | 删除数组中的第一个元素 |
unset array_name | 删除整个数组 |
通过export命令,可将作为它参数的变量导出到子shell中,并使之在子shell中有效。
4.2.2 环境变量
Linux是一个多用户的操作系统。多用户意味着每个用户登录系统后,都有自己专用的运行环境。而这个环境是由一组变量所定义,这组变量被称为环境变量。用户可以对自己的环境变量进行修改以达到对环境的要求。
Shell用环境变量来获取系统信息、存储有关shell会话和工作环境的信息和配置信息。环境变量也可用来存储永久数据,这些数据可以是用来识别用户账户、系统、shell的特性以及任何其他需要存储的数据。
Bash shell中,环境变量分为两类:1全局变量 2局部变量
全局环境变量不仅对shell会话可见,对所有shell创建的子进程也可见。可使用env命令查看。
局部环境变量则只对创建它们的shell可见。可使用set命令查看。
<span style="font-size:14px;">查看全局环境变量的命令:printenv $ printenv TERM=vt100 SHELL=/bin/bash XDG_SESSION_COOKIE=4e89c702f201d9551a9ed9a653f35a9a-1409769542.760812-1100647347 SSH_CLIENT=192.168.0.100 16257 22 SSH_TTY=/dev/pts/1 USER=lincoln LS_COLORS=rs=…. MAIL=/var/mail/lincoln PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games PWD=/home/lincoln LANG=en_US.UTF-8 SPEECHD_PORT=7560 SHLVL=1 HOME=/home/lincoln LANGUAGE=en_US:en LOGNAME=lincoln SSH_CONNECTION=192.168.0.100 16257 192.168.0.106 22 LESSOPEN=| /usr/bin/lesspipe %s LESSCLOSE=/usr/bin/lesspipe %s %s _=/usr/bin/printenv </span>
常见环境变量 | |
环境变量 | 说明 |
HOME | 当前用户的主目录 |
PATH | 以冒号分隔的用来搜索命令的目录列表 |
HISTSIZE | 历史记录数 |
LOGNAME | 当前用户的登录名 |
HOSTNAME | 主机的名称 |
SHELL | 当前用户shell类型 |
LANGUGE | 语言相关的环境变量 |
MAIL | 当前用户的邮件存放目录 |
IFS | 输入域分隔符。当shell读取输入时,它给出用来分隔单词的一组字符,它们通常是空格、制表符和换行符 |
PS1 | 命令提示符。root用户是#,普通用户是$ |
PS2 | 二级提示符。默认是>字符 |
Shell特殊内置变量通常也被称为参数变量,主要被shell脚本用来从命令行接收参数、或者被函数用来保存传给它的参数。
参数变量 | 说明 |
$0 | Shell脚本的名字 |
$# | 传递给脚本的参数个数 |
$$ | Shell脚本的进程号,通常用它来生成一个唯一的临时文件,如/tmp/tmpfile_$$ |
$1, $2, … | Shell脚本的参数,第1个参数、第2个参数、… |
$* | 在一个变量中列出所有的参数,各个参数之间用环境变量IFS中的第一个字符分隔开。 |
$@ | 除了被双引号引用的情况,含义与$*相同,且不使用IFS环境变量 |
"$*" | 其值为"$1 $2 $3" |
"$@" | 其值为"$1" "$2" "$3" |
$- | 当前的sh选项设置 |
$? | 已执行的上一条命令的退出值 |
$! | 最后一个进入后台的作业的PID |
重定向输出 | |
ps > psoutput.txt | 将标准输出重定向到文件psoutput.txt。默认情况下,如果该文件已经存在,其内容将被覆盖。 命令:set –o noclobber设置noclobber选项,改变默认行为,从而阻止重定向操作对一个已有文件的覆盖。 命令:set +o noclobber取消该选项。 |
ps >> psoutput.txt | 将标准输出内容附加到一个文件的尾部 |
Kill –HUP 1234 2>killerr.txt | 将标准错误重定向到killerr.txt文件。文件描述符加在>操作符前面,可重定向其对应的文件 |
Kill –l 1234 >killouterr.txt 2>&1 | 将标准输出重定向到文件killouterr.txt,然后将标准错误输出重定向到与标准输出相同的地方。 |
重定向输入 | |
more < killout.txt | 将killout.txt文件重定向标准输入 |
管道操作符| | |
ps | sort > pssort.out | 等价于: ps > psout.txt sort psout.txt > pssort.out |
引号 | |
myvar="Hi there" | 如果想在一个参数中包含一个或多个空白字符,须给参数加上引号 |
echo "$myvar" | $变量表达式放在双引号中,变量会被替换为它的值。结果:Hi there |
echo '$myvar' | $变量表达式放在单引号中,变量不会发生替换。结果:$myvar |
echo \$myvar | \字符取消$的特殊含义。结果:$myvar |
反引号 | |
test=`date` | 反引号允许将shell命令的输出赋值给变量 |
if语句(条件为真值为0,条件为假值为1) | |
if test … then … fi | if [ … ];then … fi |
if test … then … else … fi | if [ … ] then … else … fi |
if test … then … elif test … then … else … fi | if [ … ] then … elif [ … ] then … else … fi |
case语句 | |
case variable in pattern [ | pattern] …) statements;; pattern [ | pattern] …) statements;; … esac |
字符串比较 | 结果 |
string1 = string2 或 str1 == str2 | 如果两个字符串相同则结果为真(值为0) |
string1 != string2 | 如果两个字符串不同则结果为真 |
-n string | 如果字符串不为空则结果为真 |
-z string | 如果字符串为空则结果为真 |
算术比较 | 结果 |
expression1 –eq expression2 | 如果两个表达式相等则结果为真 |
expression1 –ne expression2 | 如果两个表达式不相等则结果为真 |
expression1 –gt expression2 | 如果expression1大于expression2则结果为真 |
expression1 –ge expression2 | 如果expression1大于等于expression2则结果为真 |
expression1 –lt expression2 | 如果expression1小于expression2则结果为真 |
expression1 –le expression2 | 如果expression1小于等于expression2则结果为真 |
!expression | 如果表达式为假则结果为真,反之亦然 |
文件条件测试 | 结果 |
-d file | 如果文件是一个目录则结果为真 |
-f file | 如果文件是一个普通文件则结果为真 |
-g file | 如果文件的set-group-id位被设置则结果为真 |
-u file | 如果文件的set-user-id位被设置则结果为真 |
-s file -e file | 如果文件的大小不为0则结果为真 如果文件存在则结果为真 |
-r file | 如果文件可读则结果为真 |
-w file | 如果文件可写则结果为真 |
-x file | 如果文件可执行则结果为真 |
方式1:
与:
if [ 条件1 ] && [ 条件2 ] && [ 条件3 ]; then ... fi
说明:先判断条件1是否为真,当条件1不为真时,直接退出;当条件1为真时,再去判断条件2是否为真。
或:
if [ 条件1 ] || [ 条件2 ] || [ 条件3 ]; then ... fi
非:
if [ ! 条件 ]; then ... fi
方式2:
与: if [ 条件1 -a 条件2 ]; then ... fi
说明:同时判断条件1和条件2是否为真。
或: if [ 条件1 -o 条件2 ]; then ... fi
非: if [ !条件 ]; then ... fi
4.4 循环语句
for循环语句 | |
for variable in values do statements done | 循环处理一组值。这组值可以是任意字符串的集合。for in 把values字符串按照空格划分。 |
while循环语句 | |
while test command do statements done | 只有测试条件成立,while命令才会继续遍历执行。适合重复执行一个命令序列,但又不知道执行次数的情况 |
until循环语句 | |
until tesst command do statements done | 与while命令工作方式完全相反。只有测试命令的退出状态码非零,until命令才会继续执行。 |
名称 | 说明 | 语法 |
合并匹配模式 | | | var1 | var2 | var3 | … |
AND列表 | && | statement1 && statement2 && … |
OR列表 | || | statement1 || statement2 || … |
语句块 | {} | { statement1 … } |
4.5 命令
Shell程序内部可执行两类命令:
<1>外部命令,即可以在命令提示符中执行的普通命令。
<2>内部命令,即在shell内部实现的内置命令。
4.5.1 break命令
break命令在控制条件未满足之前,跳出for、while或until循环。默认情况下,break只跳出一层循环。也可为break提供数值参数来表明需要跳出的循环层数,但不建议这么做。
4.5.2 continue命令
continue命令使for、while或until循环跳到下一次循环继续执行,循环变量取循环列表中的下一个值。也可为continue提供数值参数来表明需要跳过几次循环。
4.5.3 :命令
冒号(:)命令是一个空命令。
作用1>简化条件逻辑。
<span style="font-size:14px;">if [ -f fred ]; then : else echo file fred did not exist fi </span>
作用2>true的别名
while : 实现了一个无限循环,代替更常见的while true。
作用3>:${var:=value} #说明:当var为未赋值或为空时,将value的值赋给var。若没有前面的冒号:,则${var:=value}会报错。
4.5.4 .命令
通常,当一个脚本执行一条外部命令或脚本程序时,它会创建一个新的环境(一个子shell),命令将在这个心环境中执行,在命令执行完毕后,这个环境被丢弃,留下退出码返回给父shell。
外部的source命令和点(.)命令在执行脚本程序中列出的命令时,使用的是调用该脚本程序的同一个shell。
4.5.5 echo命令
echo命令用来输出结尾带有换行符的字符串。
echo hello world | 结果:hello world |
echo "you're lincoln?" | 结果:you're lincoln? |
echo 'do you know "lincoln"' | 结果:do you know "llincoln" |
1>echo –n “stringto output”
2>printf “stringto output”
4.5.6 eval命令
eval命令用来对参数进行求值。
<span style="font-size:14px;">foo=10 x=foo y='$'$x echo $y 结果输出foo foo=10 x=foo eval y='$'$x echo $y 结果输出:10 </span>
4.5.7 exec命令
exec的典型用法是将当前shell替换为一个不同的程序。
exec wall "Thanksfor all the fish"
该命令会用wall命令替换当前的shell。脚本程序中exec命令后面的代码都不会执行,因为执行这个脚本的shell已经不存在。
4.5.8 exit n命令
exit命令使脚本程序以退出码n结束运行。
如果脚本程序在退出时不指定一个退出状态,那该脚本中最后一条被执行命令的状态将被用作为返回值。
4.5.9 export命令
export将作为它参数的变量导出到子shell中,并使之在子shell中有效。
在默认情况下,在一个shell中被创建的变量在这个shell调用的子shell中是不可用的。export命令把自己的参数创建为一个环境变量,而这个环境变量可以被当前程序调用的其他脚本和程序看见。
<span style="font-size:14px;">#!/bin/sh #this file is export2.sh echo “$foo” echo “$bar” </span>
<span style="font-size:14px;">#!/bin/sh #this file is export1.sh foo=”The first meta-syntactic variable” export bar=”The second meta-syntactic variable” export2.sh</span>
$ export1.sh
4.5.10 expr命令
expr命令将它的参数当作一个表达式来求值。
x=$(expr $x+1)
expr命令可以完成许多表达式求值计算。
表达式求值 | 说明 |
expr1 | expr2 expr1 & expr2 expr1 = expr2 expr1 > expr2 expr1 >= expr2 expr1 < expr2 expr1 <= expr2 expr1 != expr2 expr1 + expr2 expr1 – expr2 expr1 * expr2 expr1 / expr2 expr1 % expr2 | 如果expr1非零,则等于expr1,否则等于expr2 只要有一个表达式为零,则等于零,否则等于expr1 等于 大于 大于等于 小于 小于等于 不等于 加法 减法 乘法 除法 取余 |
最新版本的shell才提供printf命令,以产生格式化的输出。
语法:printf "formatstring" parameter1 parameter2 …
4.5.12 return命令
return命令的作用是使函数返回。
return命令有一个数值参数,这个参数在调用该函数的脚本程序里被看做是该函数的返回值。如果没有指定参数,return命令默认返回最后一条命令的退出码。
4.5.13 set命令
set命令的作用是为shell设置参数变量。许多命令的输出结果是以空格分隔的值,如果需要使用输出结果中的某个域,这个命令就非常有用。
<span style="font-size:14px;">#!/bin/sh echo the date is $(date) set $(date) echo the month is $1 exit 0 </span>
4.5.14 shift命令
shift命令把所有参数变量左移一个位置,使$2变成$1,$3变成$2,以此类推。原来$1的值将被丢弃,而$0扔保持不变。
如果调用shift命令时指定了一个数值参数,则表示所有的参数将左移指定的次数。
<span style="font-size:14px;">#!/bin/sh while [ “$1” != “” ]; do echo “$1” done exit 0 </span>4.5.15 trap命令
trap命令用于指定在接收到信号后将要采取的行动。trap命令的一种常见用途是在脚本程序被中断时完成清理工作。
trap -l命令用来查看信号编号及其关联的名称:
$ trap -l 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR 31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3 38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8 43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13 48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12 53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7 58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2 63) SIGRTMAX-1 64) SIGRTMAX |
第一个参数command是接收到指定信号时将要采取的动作。
第二个参数signal是要处理的信号名。
脚本程序通常是以上从到下的顺序解释执行的,所以你必须在你想保护的那部分代码之前指定trap命令。
重置某个信号的处理方式到期默认值,只需将command设置为-
要忽略某个信号,只需把command设置为空字符串''
<span style="font-size:14px;">#!/bin/sh trap 'rm –f /tmp/my_tmp_file_$$’ INT echo creating file /tmp/my_tmp_file_$$ date > /tmp/my_tmp_file_$$ echo “Press interrupt (CTRL-C) to interrupt …” while [ -f /tmp/my_tmp_file_$$ ]; do echo File Exist sleep 1 done echo The file no longer exist echo creating file /tmp/my_tmp_file_$$ date > /tmp/my_tmp_file_$$ echo “press interrupt (control-C) to interrupt …” while [ -f /tmp/my_tmp_file_$$ ]; do echo File Exists sleep 1 done echo we never get here exit 0 </span>4.5.16 unset命令
unset命令的作用是从环境中删除变量或函数。这个命令不能删除shell本身定义的只读变量(如IFS)
<span style="font-size:14px;">#!/bin/sh foo=”Hello,world” echo $foo unset foo echo $foo </span>4.5.17 find命令
find是用于搜索文件的命令。
语法:find [path][options] [tests] [actions]
选项options | 含义 |
-depth -follow -maxdepths N -mount(或-xdev) | 在查看目录本身之前先搜索目录的内容 跟随符号链接 最多搜索N层目录 不搜索其他文件系统中的目录 |
测试tests | 含义 |
-atime N -mtime N -name pattern -newer otherfile -type c -user username | 文件在N天之前被最后访问过 文件在N天之前被最后修改过 文件名匹配提供的模式,pattern由引号括起 文件比otherfile文件要新 文件的类型为c,c是一个特殊类型,最常见的是d(目录)和f(普通文件) 文件的拥有者是指定的用户username |
操作符,短格式 | 操作符,长格式 | 含义 |
! -a -o | -not -and -or | 测试取反 两个测试都必须为真 两个测试有一个必须为真 |
动作actions | 含义 |
-exec command -ok command -ls | 执行一条命令。该动作必须用\;字符对结束 处理前提示用户确认,其他同上 打印文件名 对当前文件使用命令ls-dils |
grep即GeneralRegular Expression Parser(通用正则表达式解析器)的简写。使用find命令在系统中搜索文件,而使用grep命令在文件中搜索字符串。常见的用法是在使用find命令时,将grep作为传递给-exec的一条命令。
grep命令使用一个选项、一个要匹配的模式和要搜索的文件。如果没有提供文件名,则grep搜索标准输入。
语法:grep [options] PATTERN [FILES]
选项options | 含义 |
-c -E -h -i -l -v | 输出匹配行的数目,而不是输出匹配的行 启用扩展表达式 取消每个输出行的普通前缀,即匹配查询模式的文件名 忽略大小写 只列出包含匹配行的文件名,而不输出真正的匹配行 对匹配模式取反,即搜索不匹配行而不是匹配行 |
语法 |
function_name() { statements } |
当一个函数被调用时,脚本程序的位置参数($*、$@、$#、$1、$2等)会被替换为函数的参数。
返回值:
函数返回数字值——return命令。
函数返回字符串值——让函数将字符串保存在一个变量中,该变量可以在函数结束之后被使用。
局部变量
函数中声明局部变量——local关键字
<span style="font-size:14px;">#!/bin/sh yes_or_no() { echo "Is your name $* ?" while true do echo -n "Enter yes or no: " read x case "$x" in y | yes ) return 0;; n | no ) return 1;; * ) echo "Answer yes or no" esac done } echo "Original parameters are $*" if yes_or_no "$1" "$2" then echo "Hi $1, nice name" else echo "Never mind" fi exit 0 </span>
4.7 调用另一个脚本
shell调用另一个shell脚本有三种方法:
1>fork (格式: /directory/script.sh)
fork是最普通的, 就是直接在脚本里面用/directory/script.sh来调用script.sh这个脚本.
运行的时候开一个sub-shell执行调用的脚本,sub-shell执行的时候, parent-shell还在。
sub-shell执行完毕后返回parent-shell. sub-shell从parent-shell继承环境变量.但是sub-shell中的环境变量不会带回parent-shell
<span style="font-size:14px;">$ cat 1.sh #!/bin/bash var=hello world echo $var echo '=====================array=============================' array=(1 2 3 4 5 6 78) echo ${array[*]:1:3} echo ${array[*]:0} echo ${array[*]:1} echo ${array[*]:0:4} echo ${array[*]:0:5} echo ${array[*]:1:4} echo ${array[*]:1:5} echo ${array[*] %8} </span>
<span style="font-size:14px;">$ cat 2.sh #!/bin/sh echo "this file is 2.sh" echo "call 1.sh..." ./1.sh exit 0 $ </span>
2>exec (格式:exec /directory/script.sh)
exec与fork不同,不需要新开一个sub-shell来执行被调用的脚本. 被调用的脚本与父脚本在同一个shell内执行。但是使用exec调用一个新脚本以后, 父脚本中exec行之后的内容就不会再执行了。这是exec和source的区别。
<span style="font-size:14px;">$ cat 1.sh #!/bin/bash var=hello world echo $var echo '=====================array=============================' array=(1 2 3 4 5 6 78) echo ${array[*]:1:3} echo ${array[*]:0} echo ${array[*]:1} echo ${array[*]:0:4} echo ${array[*]:0:5} echo ${array[*]:1:4} echo ${array[*]:1:5} echo ${array[*] %8} </span>
<span style="font-size:14px;">$ cat 2.sh #!/bin/sh echo "this file is 2.sh" echo "call 1.sh..." <strong>exec</strong> ./1.sh exit 0 $ </span>
3>source (格式:source /directory/script.sh)
与fork的区别是不新开一个sub-shell来执行被调用的脚本,而是在同一个shell中执行. 所以被调用的脚本中声明的变量和环境变量, 都可以在主脚本中得到和使用.
<span style="font-size:14px;">$ cat 1.sh #!/bin/bash var=hello world echo $var echo '=====================array=============================' array=(1 2 3 4 5 6 78) echo ${array[*]:1:3} echo ${array[*]:0} echo ${array[*]:1} echo ${array[*]:0:4} echo ${array[*]:0:5} echo ${array[*]:1:4} echo ${array[*]:1:5} echo ${array[*] %8} </span>
<span style="font-size:14px;">$ cat 2.sh #!/bin/sh echo "this file is 2.sh" echo "call 1.sh..." <strong>source</strong> ./1.sh exit 0 $ </span>
5 shell调试
跟踪脚本程序中复杂错误的主要方法是设置各种shell选项。如,可以在调用shell时加上命令行选项,或是使用set命令。
命令行选项 | set选项 | 说明 |
sh –n <script> sh –v <script> sh –x <script> sh –u <script> | set –o noexev set –n set –o verbose set –v set –o xtrace set –x set –o nounset set -u | 只检查语法错误,不执行命令 在执行命令之前回显它们 在处理完命令之后回显它们 如果使用了未定义的变量,就给出出错信息 |
Linux所有的任务都可以通过命令行来完成,而这可以通过shell来实现。
shell可以将简单的任务自动化。
shell强调易于配置、易于维护和可移植性,所以它适合编写一些执行相对简单的任务的小工具。又因为是解释执行的,所以不适合用来完成时间紧迫型和处理器忙碌型的任务。
相关文章推荐
- Linux程序设计笔记 第2章shell程序设计
- linux----笔记1---shell程序设计
- Linux程序设计-学习笔记-第二章shell程序设计
- [C++程序语言设计笔记一]面向对象编程抽象,继承,重写基本介绍
- 程序设计实践笔记---风格
- Linux程序设计读书笔记:第二章 shell程序设计
- Shell笔记第三天 后台运行程序
- Shell程序设计
- 几个shell程序设计小知识(shell常识部分)
- shell 程序设计入门 比较两个数的大小
- Qt学习笔记,Qt程序架构设计要旨
- JohnConnor设计模式笔记(二) 程序世界里的复印机-原型模式与浅复制/深复制
- Shell 基础篇---介绍几个shell程序设计小知识
- 操作系统学习笔记(40)--Shell程序
- shell程序设计001
- 几个shell程序设计小知识(shell常识部分)
- MC55开发之GPRS远程登陆程序的具体设计(独家整理!保证是你见过的MC55开发最全的笔记~~)
- shell程序设计(3)
- shell程序设计小知识
- Qt学习笔记,Qt程序架构设计要旨