Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2374069
  • 博文数量: 473
  • 博客积分: 12252
  • 博客等级: 上将
  • 技术积分: 4307
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-12 10:02
文章分类

全部博文(473)

文章存档

2012年(8)

2011年(63)

2010年(73)

2009年(231)

2008年(98)

分类:

2009-04-07 11:29:46


我们的讨论伴随着一个问题开始:
$ cat >>test1< > 111111
> 111111
> 111111
> EOF
$ cat test1
111111
111111
111111
$
问题是这命令是怎么执行的?
( 注:不要用test这个名子来作测试,因为系统中的确有一个test程序/usr/bin/test)
如果知道答案,当然可以把问题分成几部分,要了解 cat 做了什么, >> , << ,还有EOF这里做了什么,以及它们的执行顺序。

首先我们要了解,这里 cat做了什么?
cat [OPTION] [FILE]...
Concatenate FILE(s), or standard input, to standard output.

当没 FILE时就是读standard input了,
hyang0:~$ cat
aaaa
aaaa
bbb
bbb
a
a
hyang0:~$
它会把读的每一行都立即打印出来,所以你看到有两行相同的,其中一行是cat向tandard output输出的。v如果你把它重定向到一个文件,效果会如下:
hyang0:~$ cat >t
aaaa
bbbb
c
a
hyang0:~$ cat t
aaaa
bbbb
c
a
hyang0:~$
这里要注意,cat是把stdin的所有输入,重定向到文件里,而不是把每一行都重定向文件里,所以不是你所想的文件里只有最后一行前面的都被覆盖。

另外还要注意,使用cat 从stdin输入时,结束时用不要用,不然你的最后一行会被吃掉,如:
hyang0:~$ cat >t
adfas
dfa
aaa
hyang0:~$ cat t
adfas
dfa
hyang0:~$

现在再回到这个例子:
$ cat >>test1< > 111111
> 111111
> 111111
> EOF
$ cat test1
111111
111111
111111
$
EOF代表文件结束吗? 可能它在C中表示,在这里,它只是个分隔符而已。
其中 << 表示重定向(追加), <

Here documents

当要将几行文字传递给一个命令时,用here documents是一种不错的方法。对每个脚本写一段帮助性的文字是很有用的,此时如果使用here documents就不必用echo函数一行行输出。Here document以 << 开头,后面接上一个字符串,这个字符串还必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文件进行重命名,并且使用here documents打印帮助:

#!/bin/sh

# we have less than 3 arguments. Print the help text:
if [ $# -lt 3 ] ; then
cat << 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
exit 0
fi
aaa
OLD="$1"
NEW="$2"
# The shift command removes one argument from the list of
# command line arguments.
shift
shift
# $* 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
fi
done

这个示例有点复杂,我们需要多花点时间来说明一番。第一个if表达式判断输入命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助文字后程序退出。如果输入参数等于或大于3个,我们 就将第一个参数赋值给变量OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个参数从参数列表中删除,这样原来的第三个 参数就成为参数列表$*的第一个参数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接着我们判断该文件是否存在,如果存在则 通过sed命令搜索和替换来产生新的文件名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了目的:得到了旧文件名和新文件名。然后使用 mv命令进行重命名。

Okay, 现在明白什么是here documents了吧,你可以把它当成一个锚标,锚定一段文本,才用来作help说明的。
在我们这里,
$ cat >>test1< > 111111
> 111111
> 111111
> EOF
$ cat test1
111111
111111
111111
$
我们也来细分一下,
hyang0:~$ test1< > A
> B
> C
> ABC
bash: test1: command not found
hyang0:~$
这个例子说明,当执行带here documents的命令时,它会先等你把 documents内容输完,然后重定向到前面。这里 它就把test1 当程序了,并把stdin内容重定向它,如果test1是cat 就没问题了。

这里我们要把下面这个当成一条语句,出现 >,它表示命令还没完,等待输入。
$cat >>test1< > 111111
> 111111
> 111111
> EOF
$
同时要解析这条语句,我们还要明白,shell在解析命令时,它会先处理重定向,最后才组合命令,上面那条最终执行的就是   cat ,其它都被重定向掉了,   在执行cat之前, shell做了很多重定向的工作。
我们把
< 111111
111111
111111
EOF
这段的内容存在文件中,那么上述命令可以转化成下面这个样子:
hyang0:~$ vi test2         //把上述内容写到test2中
hyang0:~$ cat test2
111111
111111
111111
hyang0:~$ cat 0 111111
111111
111111
hyang0:~$ cat 0test1   //最终可以转化成这样
hyang0:~$ cat test1
111111
111111
111111
hyang0:~$

[OVER]

阅读(2311) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~