Wednesday, 13 June 2007

shell的重定向

新建一个文本文件包含所需要的脚本。举例,我会使用pico编辑器写一个脚本用来运行程序tar,带上必要的可选项可以用来解压从因特网下载下来的*.tar的文件(我好像总是记不住tar的所有参赛)。我决定把我的脚本名称叫做“untar”:

pico untar

因为在我的当前工作目录里untar文件不存在,所有pico文本编辑器自动创建这个文件,现在,我输入以下内容:

#!/bin/bash

echo this is the script file $0

echo untarring the file $1

# this calls tar with options -xvzf (extract,

# verbose, filter through gzip, input filename)

tar -xvzf $1

我使用O保存这个文件,然后X退出。

脚 本的第一行,以“#!”开始是特别的提示-它告诉shell应该用哪一个程序来解释我的脚本。在这个例子里,我使用bash shell /bin/bash。第一行必须使用“#!”开头,否则脚本不会运行(系统认为是一个文本文件)。其他以“#”开始的行是注释行只是给作者和读者使用的, 计算机将跳过这些行。

在以上脚本里,参数$0, $1, $2…是传递到脚本里面的参数。举个例子,如果我运行我的脚本名“myscript”带七个参数如下:

myscript a b c d e f g

那么,参赛$0就是myscript, $1就是a, $2就是b,$3就是c,依此类推。

脚本的第二行和第三行,echo命令输出所有在它后面同一行上的文本,然后扩展在脚本里对应的参数$0和$1。第四行和第五行是我写的注释文本,提醒我在这个脚本里要做的事情。只有最后一行是真正起作用的。

一旦脚本已经写好,我把文件属性改成对文件拥有者是“可执行”的:

chmod u+x untar

然后我的脚本就可以这样运行了:

./untar my_tar.tar.gz

Liunx脚本的确非常丰富,灵活,功能强劲,还可能有点复杂。然而,对于日常任务编写一些简单脚本,它并不需要什么特别高深的知识。你可以把一些要用到的命令放在一起,一个接一个,输入到文件里。我使用脚本很频繁是因为我太懒了,不想一次一次的输入相同的命令。

一个最简单的方法,可以把一组命令放在文本文件里然后使用source命令传递给shell让它直接运行:

source my_file

这个时候就不需要在文本第一行加上“#!”的标志了。

3.4.6 引号的含义

一般来说,以下字符对于shell有特殊的含义:

\ ' " ` < > [ ] ? | ; # $ ^ & * ( ) =

这里有四种不同的符号:反斜杠(\),单引号(‘),双引号(“),反向单引号(`)。

反斜杠(\)表示:关闭后面字符的特殊含义

单引号(‘)表示:关闭在两个单引号之间所有字符的特殊含义

双引号(“)表示:关闭在两个双引号之间所有字符的特殊含义除了$ ` \

反向单引号(`)表示:告诉shell首先运行两个反向单引号之间的命令,然后把得到的结果再传递给两个单引号之外的命令。同样的功能也可以通过“$command”命令来实现,而且可能会更方便。

举个例子,我可以创建一个奇怪的目录名叫做“*”通过使用“\”或者“’”符号:

mkdir \*

mkdir ’*’

这屏蔽了“*”对于shell的特别含义。如果没有“\”,“*”意味着当前目录下所有文件。

3.4.7 输入输出重定向

有三个最重要的输入输出流:标准输入(stdin),标准输出(stdout),标准错误(stderr)。它们对于控制台(“控制台”指的是键盘用于输入,屏幕用于输出)来说是缺省的,但是它们可以被重定向。

重定向标准输出,可以使用“>”符号,举例:

dir my_dir > filelisting.txt

将把dir命令的标准屏幕输出重定向到文本文件 filelisting.txt文件里,所以屏幕上没有任何输出。这个文件可以用来编辑(比如使用pico文本编辑器)或者合并到其他的文件里。

重定向标准错误,可以使用结构“2>”,举例:

dir my_dir 2> errorlisting.txt

以上命令将送标准输出到屏幕上,如果没有错误信息,将没有任何信息写到errorlisting.txt文件里。如果出错,则没有什么东西输出到屏幕,而文件errorlisting.txt将包含错误信息。错误信息有可能是这样的:

dir: my_dir: Permission denied

最后,我也可以把标准输出和标准错误一起输出到同一个文件里,

dir my_dir > file_and_error_listing.txt 2>&1

以上命令先重定向标准输出到文本文件里,然后再重定向标准错误到和标准输出同样的位置。它如何实现可能看起来有点古怪,但是是可行的。

在以上的例子里,如果重定向的文件已经存在,该文件会被覆盖。如果你要追加到该文件的末尾,可以使用“>>”符号,以上的例子就变成:

dir my_dir >> filelisting.txt

dir my_dir 2>> errorlisting.txt

dir my_dir >> file_and_error_listing.txt 2 > &1

如果你对“2>”感到很迷惑,这里有一个简单的办法可以帮你理解,标准流有标准的解析器:“0”代表标准输入,“1”代表标准输出,“2”代表标准错误。

dir my_dir > file.txt

是以下命令的简写方式:

dir my_dir 1 > file.txt

那么以下命令就是用来输出标准错误:

dir my_dir 2 > file.txt

还有,你还可以使用符号“|”(管道命令)把一个命令的标准输出送到另外一个命令的标准输入。在以下这个标准的例子里,dir命令的标准输出通过管道输入到命令more里(输出满屏的时候自动暂停):

dir | more

你还可以使用“tee”命令把标准输出同时写到文件和屏幕,

dir | tee filelisting.txt

tee是“T型连接器”的模拟音,在管道中的主要的用途是分流。

这个部分这样都用来讲述标准输出重定向,对于标准输入重定向不像标准输出重定向那么有用,但是它可以使用以下方式实现:

cat <>

还有一种叫做“直接插入式”的标准输出,可以通过“<<”来实现。不要管它了,看起来对我没有什么实际用处。不过,如果你真的想知道,这里有一个例子(这里“>”式第二个提示符)

cat <<>

> my_line_from_the_keyboard

> another_line_from_the_keyboard

> my_marker

除了重定向到常规文件和“过滤器”之外(如以上的例子所示),你还可以重定向到设备和其他特殊文件。看下面这些例子。

重定向到设备文件的例子。以下命令将显示文件列表到第四个文本终端:

dir > /dev/tty4

以下是一个重定向到一个特殊的FIFO(先进先出)文件的例子。该命令送信息”you are lucky”到叫做“lucky”的ICQ用户UIN 7777777 (假定你已经用你的ICQ程序连接到ICQF服务器上了)

echo message 7777777 “you are lucky” < ~/.licq/licq_fifo

以上的例子能够工作是因为在你licq目录下的文件“licq_fifo”是一个特别的FIFO序列文件。以上这个例子,对比于在图形用户界面下的ICQ程序有什么特别有用的地方吗?举个例子,你可以写一个短的脚本带上多个信息给你的那些ICQ伙伴们:

#!/bin/bash

echo Messaging UIN: $1 Message: $2 Times: $3

# The next command puts puts your licq in the status "on-line, invisible".

echo 'status *online' > ~/.licq/licq_fifo

c=0

while [ $c -le $3]

do

echo message $1 $2 > ~/.licq/licq_fifo

c=`expr $c + 1`

echo $c " "

done

echo 'status offline' > ~/.licq/licq_fifo

echo "all done"

这个例子利用了licq通信模型(FIFO文件)和简单的文件重定向功能,给你一个关于如何 “自动化”licq的主意。

3.4.8 Shell的特殊字符(metacharacters)

一般来说,这些字符对于shell有特别的含义:

\ ' " ` < > | ; ( ) [ ] ? # $ ^ & * =

以下是这些字符的含义:

\ ‘ “ 和 ‘ 主要用来注释,前面已经描述过 (参见 3.4.6)。

< 和 > 主要用来输入和输出重定向

| 是管道命令,管道左边的标准输出是管道右边的标准输入

; 用于间隔在同一命令行上的几个命令

间用于分开命令的字符和单词

完成一条命令或者一组命令

( ) 用于封装需要使用不同的shell启动的命令, 比如 ( dir )

{ } 用于封装要用当前shell启动的一组命令,比如 { dir },需要空格间隔

& 使当前命令在后台运行(有它自己独立的进程),所以下一条命令不需要等待前一条命令结束才能开始。

* 当搜索文件时,它匹配除了以“.”开头的所有文件

?当搜索文件时,它匹配任何单个字符

[ ] 当搜索文件时,它匹配任何在[]里面的单个字符

&& 是用于连接两个命令的“与操作”,

command1 && command2, 只有当command1退出状态为0时(没有错误),command2才会被执行。比如, cat file1 && cat file2 只有当file1正常显示时, file2才能被显示。

|| 是用于连接两个命令的“或操作”

command1 || command2, 只有当command1退出状态非0时(有错误),command2才会被显示。比如:cat file1 || cat file2 只有当显示file1出错时,file2才能被显示

= 指定值给变量

举例,命令me=blahblah设定值“blahblah”给变量“me”,我可以输出变量名:

echo $me

$ 预处理扩展变量名

变量可以使用“=”来设定值,也可以通过预先变量设定来设置

$0 被执行的shell脚本的名称

$# 按位置对应的命令输入参数, $1第一个参赛, $2第二个参数, $3第三个参数…直到$9

$* 扩展所有的位置参数给命令

$@ 扩展所有的位置参数给命令,但是当“$@”使用时,参数个别标注

Pasted from <http://www.blogjava.net/pdw2009/archive/2006/09/16/70061.html>

No comments:

My photo
London, United Kingdom
twitter.com/zhengxin

Facebook & Twitter