入门
Shell脚本最常用于系统管理工作,或者是用于结合现有的程序以完成小型的、特定的工作。一旦你找出完成工作的方法,可以把用到的命令串在一起,放进一个独立的程序或者脚本里,此后只要直接执行该程序便能完成工作。此外,如果你写的程序很有用,其他人可以利用该程序当作一个黑盒来使用。他是一个可以完成工作的程序,但我们不必要知道它是如何工作的。
脚本编译语言和编译型语言的差异
编译型语言的好处是:高效。缺点是:它们多半运作于底层,所处理的是字节、正数、浮点数或者是其他机器层级的对象。如:C++很难实现一个简单的操作:将一个目录里所有的文件复制到另一个目录中。
脚本编程语言通常是解释型(interpreted)的。这类程序的执行是由解释器读入程序代码,并将其转换成内部的形式,再执行。但解释器本身是一般的编译型程序。
为什么要使用Shell脚本
使用脚本编程语言的好处是:他们多半运行在比编译型语言还高的层级,能够轻易处理文件与目录之类的对象。缺点是:效率通常不如编译型语言。
之所以用Shell脚本是基于:
简单性
Shell是一个高级语言,通过它,可以简洁地表达复杂的操作。
可移植性
使用POSIX(Portable Operating System Interface)所定义的功能,可以做到脚本无需修改就可在不同的系统上执行。
开发容易
可以在短时间内完成一个功能强大又好用的脚本。
位于第一行的#!
当Shell执行一个程序时,要求Unix内核启动一个新的进程(process),在便在该进程里执行指定的程序。内核知道怎样为编译型程序执行,但Shell是解释型程序,当Shell要求内核执行时,内核无法执行,会回应”not executable format file”
不是可执行的格式文件的错误信息。Shell收到此错误信息时,就会说“这不是编译型程序,是Shell脚本”,接着会启动一个新的/bin/sh
副本来执行该程序。
当系统只有一个Shell时,退回到/bin/sh
的机制非常简单。但是现行的UNIX系统都会拥有好几个Shell,因此需要通过一种方式,告知UNIX内核应该以哪个Shell来执行所指定的Shell脚本。这么做有助于执行机制的通用化,让用户得以直接引用任何的程序语言解释器,而非只是一个命令Shell。方法是,通过脚本文件中特殊的第一行来设置:在第一行的开头处使用#!
这两个字符。
当一个文件中开头的两个字符是#!
时,内核会扫描改行其余的部分,看是否存在可用来执行程雪的解释器的完整路径(中间如果出现任何空白符号都会略过)。此外,内核还会扫描是否有一个选项要传递给解释器。内核会以指定的选项,再搭配命令行的其他部分来引用解释器。
Shell的基本元素
命令与参数
Shell最基本的工作就是执行命令。
- 格式:以空白(space或者Tab)隔开命令行中各组成部分。
- 命令的名称是命令行的第一个对象。通常后面会跟着选项,任何额外的参数都会放在选项之后。
- 选项的开头是一个破折号(或减号),后面接着一个字母。选项是可有可无的,有的可能需要加上参数。不需要参数的选项可以合并。
- 现代机对长选项也逐渐的支持了。长选项的开头是一个破折号还是两个,视程序而定。
- 分号
;
可用来分隔同一行的多条命令。Shell会依次执行这些命令。 - 如果使用的是
&
符号而不是分号,则Shell将在后台执行前面的命令。即Shell不用等到该命令完成,就可以继续执行下一个命令。
Shell识别三种基本命令:內建命令、Shell函数以及外部命令:
- 內建命令就是Shell本身所执行的命令。
- Shell函数式功能健全的一系列程序代码,以Shell语言写成,他们可以像命令那样引用。
- 外部命令就是由Shell的副本所执行的命令。
变量
变量就是为了某个信息片段所起的名字。变量值可以是空值。Shell变量名称的开头是一个字母或下划线符号,后面可以接着任意长度的字母、数字或下划线符号。变量名称的字符长度并没有限制。Shell变量可用来保存字符串值,所能保存的字符数同样没有限制。
变量赋值的方式为:先写变量名称,紧接着=
字符,最后是新值,中间完全没有任何空格。当你想取出Shell变量的值时,在变量名称前面加上$
字符。当所赋予的值内含空格时,请加上引号。
first=isaac middle=bashevis last=singer //单行可进行多次赋值
fullname="isaac bashevis singer' //值中包含空格时使用引号
oldname=$fullname //此处不需要引号
如上所示:当变量作为第二个变量的新值时,不需要使用双引号。但是使用双引号也没关系。不过,当把几个变量链接起来时,就需要使用引号了:
fullname="$first $middle $last"
简单的echo输出
语法
echo [ string ……]
用途
产生Shell脚本的输出
行为模式
echo将各个参数打印到标准输出,参数之间以一个空格隔开,并以换行符号结束。它会解释每个字符串里的转义序列。转义序列可用来表示特殊字符,以及控制其行为模式。
echo的转义序列
\a 警示字符,通常是ASCII的BRL字符
\b 退格
\c 输出中忽略最后的换行字符。这个参数之后的任何字符,包括接下来的参数,都会被忽略掉。
\f 清楚屏幕
\n 换行
\r 回车
\t 水平制表符
\v 垂直制表符
\\ 反斜杠字符
\0ddd 将字符表示成1到3的八进制数值
华丽的printf输出
printf不像echo那样会自动提供一个换行符号。必须显式地将换行符号指定成\n
。
完整的语法分为两部分:
printf format-string [arguments……]
第一部分是一个字符串,用来描述输出的排列方式,最好为此字符串加上引号。此字符串包含了按字面上显示的字符以及格式声明,后者是特殊的占位符,用来描述如何显示相应的参数。
第二部分是与格式声明相对应的参数列表。
基于I/O的重定向
重定向与管道
- 用
<
改变标准输入 用
>
改变标准输出此重定向符在目标文件不存在时,会新建一个。但如果目标文件存在的时,它就会被覆盖掉,原来的数据就会丢失。
用
>>
附加到文件如同
>
,如果目标文件不存在,>>
重定向符便会新建一个。但如果目标文件存在,他不会直接覆盖掉文件,而是将程序所产生的数据附加到文件结尾处。以
|
建立管道program1 | program2可将program1的标准输出修改为program2的标准输入。好处:管道可以使执行速度比使用临时文件的程序快上十倍。
特殊文件:/dev/null与/dev/tty
UNIX系统提供了两个对Shell编程特别有用的特殊文件。
第一个文件/dev/null,就是位桶(bit bucket)。传到此文件的数据都会被系统丢掉。相对的,读取/dev/null则会立即返回文件结束符(end-of-line)。
第二个文件是/dev/tty。当程序打开此文件时,UNIX会自动将它重定向到一个终端在与程序结合。这在程序必须读取人工输入时(比如密码)特别有用。例如:
#!/bin/sh
printf 'enter your name:\n'
stty -echo
read pass < /dev/tty
printf 'please enter your name again\n'
read pass2 < /dev/tty
stty echo
if [ $pass = $pass2 ]; then
printf 'sucess\n'
else
printf 'false\n'
fi
stty
即(set tty
)命令用来控制终端的各种设置。-echo
选项用来关闭自动打印每个输入字符的功能。stty echo
用来恢复该功能。
基于命令查找
Shell会沿着查找路径$PATH
来寻找命令,$PATH
是以冒号分割的目录列表,可以在列表指定的目录下找到所要执行的命令。
默认路径因系统而已,至少包含/bin
与/usr/bin
,如果要自己编写脚本,准备自己的bin目录来存放。步骤如下:
cd
mkdir bin
mv myShell.sh bin
PATH=$PATH:$HOME/bin
myShell.sh
要让修改永久生效,在.profile
文件中把你的bin目录假如$PATH
,每次登录时Shell都将读取.profile文件。
访问Shell脚本的参数
位置参数(position parameters)指的是Shell脚本的命令行参数(command-line arguments)。参数使用”$数字”
的形式表示,当参数大于9时,使用${数字}。
简单的执行跟踪
程序执行出错时,可以把执行跟踪(execution tracing)的功能打开。这会使Shell显示每个被执行到的命令,并在前面加”+”:一个加号后面跟着一个空格。
- 可以在执行脚本时,使用
sh –x 脚本.sh
的方式执行跟踪功能。 - 也可以在脚本中添加
set –x
打开跟踪功能,使用set +x
关闭跟踪功能。
参考资料:
Shell脚本学习指南 作者:(美)罗宾著
备注:
转载请注明出处:http://blog.csdn.net/wsyw126/article/details/52964309
作者:WSYW126