shell 输入重定向 与 Here documents
时间:2009-04-07 来源:sss0213
我们的讨论伴随着一个问题开始:
$ cat >>test1<<EOF
> 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输入时,结束时用<ctr+d>不要用<ctr+c>,不然你的最后一行会被<ctr+c>吃掉,如:
hyang0:~$ cat >t
adfas
dfa
aaa
hyang0:~$ cat t
adfas
dfa
hyang0:~$
现在再回到这个例子:
$ cat >>test1<<EOF
> 111111
> 111111
> 111111
> EOF
$ cat test1
111111
111111
111111
$
EOF代表文件结束吗? 可能它在C中表示,在这里,它只是个分隔符而已。
其中 << 表示重定向(追加), <<ABC (或者EOF,EAF,你想写什么都行), 我们称它为here documents
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<<EOF
> 111111
> 111111
> 111111
> EOF
$ cat test1
111111
111111
111111
$
我们也来细分一下,
hyang0:~$ test1<<ABC
> A
> B
> C
> ABC
bash: test1: command not found
hyang0:~$
这个例子说明,当执行带here documents的命令时,它会先等你把 documents内容输完,然后重定向到前面。这里 它就把test1 当程序了,并把stdin内容重定向它,如果test1是cat 就没问题了。
这里我们要把下面这个当成一条语句,出现 >,它表示命令还没完,等待输入。
$cat >>test1<<EOF
> 111111
> 111111
> 111111
> EOF
$
同时要解析这条语句,我们还要明白,shell在解析命令时,它会先处理重定向,最后才组合命令,上面那条最终执行的就是 cat ,其它都被重定向掉了, 在执行cat之前, shell做了很多重定向的工作。
我们把
<<EOF
111111
111111
111111
EOF
这段的内容存在文件中,那么上述命令可以转化成下面这个样子:
hyang0:~$ vi test2 //把上述内容写到test2中
hyang0:~$ cat test2
111111
111111
111111
hyang0:~$ cat 0<test2 //中间过程结果,这样看的更明白
111111
111111
111111
hyang0:~$ cat 0<test2 >test1 //最终可以转化成这样
hyang0:~$ cat test1
111111
111111
111111
hyang0:~$
[OVER]
相关阅读 更多 +