如果我想为命令、、和中的输入或输出( < myfile
、 或> myfile
)提供重定向test-commands
consequent-commands
command1
command2
if test-commands; then
consequent-commands;
until test-commands; do consequent-commands; done
while test-commands; do consequent-commands; done
command1 && command2
command1 || command2
我应该在哪里放置重定向?
例如,我看到
while read a;
do echo "$a";
done < myfile;
我想知道为什么放在< myfile
后面done
,而不是后面read a
?
这也让我思考得更广泛(作为本文的开头部分):
复合命令中出现的命令应置于何处?
重定向是输出还是输入有关系吗?
如果我将重定向放在复合命令的末尾,我如何知道重定向适用于复合命令中的哪个组件命令?
谢谢。
答案1
您可以将重定向放置在简单命令中的任何位置(即调用别名、函数、内置函数或带参数的可执行文件)。另一方面,如果您想对复合命令应用重定向,则必须在之后进行重定向。这就是 shell 语法的设计方式。例如,以下内容是等效的:
<myinput mycommand argument
mycommand <myinput argument
mycommand argument <myinput
而重定向不能移入
while …; do …; done <myinput
{ command1; command2; } <myinput
仅当复合命令以关键字或标点符号结尾时,您才能应用重定向。要将重定向应用于foo && bar
or foo; bar
or之类的内容foo | bar
,请将命令放在大括号中,例如
{ foo && bar; } <myinput
脚本
while read a; do
echo "$a"
done <myfile
和
while read a <myfile; do
echo "$a"
done
两者在语法上都是正确的,但第二个没有做任何有用的事情。命令上的重定向运算符意味着:
- 打开指定的文件。
- 将指定的文件附加到必需的文件描述符(例如 0 表示
<
)。 - 运行命令。
- 关闭文件描述符。
因此,read a <myfile
每次迭代时都会再次打开文件,这意味着它会永远读取第一行。
如果要使用 while-read 循环并希望保留循环体的周围标准输入,请从不同的文件描述符读取。
while read a <&3; do
# commands that can use stdin
done 3<myfile
重定向运算符<&3
仅执行文件描述符复制,它不会“再次打开文件”——在上面的枚举中,没有步骤 1。
答案2
对于简单的命令,重定向定位是灵活的,只要它位于同一行并且在任何;
.这些都是有效的:
command1 arg <file
<file command1 arg
command1 <file arg
从风格上来说,您会发现第一种形式通常是首选。
对于通过管道或条件连接的命令,重定向显然应该与关联命令位于同一侧。如果第一个命令必须接收输入,那么您需要:
command1 <file || command2
对于 command2 接收输入:
command1 || command2 <file
while
在,和其他块复合命令的情况下,for
将重定向放在末尾的必要性只是语法上的现实。
<file { command1 || command2; } # error
{ command1 || command2; } <file # okay
例如,复合命令在此上下文中充当单个命令,因此重定向输入不能以 command2 为目标并排除 command1。
当然,管道有时也是一种选择,因此上面的第二个示例类似于:
cat file | { command1 || command2; }
在 while 循环的情况下:
cat myfile | while read a; do ...
我在所有这些示例中都使用了输入,但同样适用于输出。需要注意的是,如果同时使用输入和输出或其他多重重定向配置。重定向是从左到右处理的。
这里还有一些阅读内容: