理解bash中的"exec 1>&2"命令

14

我看到一个包含exec 1>&2命令的Bash脚本函数,类似于:

function example()
{
    exec 1>&2
    cat <<EOT
Script requires at least one parameter.
EOT
    exit 1
} 

据我理解,exec 1>&2表示从此处开始的所有内容都将被重定向到stderr。这是一种固定的exec行为,需要熟记,还是有一些合理的解释?我的意思是,Bash脚本中的exec只是调用一个command,该command具有与Bash脚本相同的PID,一旦command完成,PID就会被终止。1>&2并不是一个命令。能否有人解释一下exec 1>&2命令背后的细节(特别是为什么问题)?


1
在这种情况下,该代码是一种冗长的写法:echo "Script requires at least one parameter" 1>&2。此外,错误消息并不是很有帮助;你必须猜测那个参数是什么。更好的消息应该是:echo "Usage: $(basename $0 .sh) filename [...]" 1>&2",以告诉你(提醒你)正确的用法和需要提供的内容。而使用四行来完成一个任务有点过头了。如果有许多行要“echo”,那么重定向就更有意义了,但仍可以使用 cat 1>&2 <<EOT,然后是“here document”。 - Jonathan Leffler
@JonathanLeffler:我同意。在一个大括号包裹的函数开头放置exec 1>&2有点邪恶,因为这个副作用会在函数返回后继续存在。(诚然,这个函数调用了exit 1,但这种惯用法甚至不应该存在。) - ruakh
@ruakh:通常在函数内部这样做并不是很好的方式,但如果这是函数预期的行为,那么这样做可能是正确的。这个习惯用法本身非常有用,如果使用得当的话。这是一个非常边缘的实例,我认为它在错误的一侧,进入了“不当使用”的领域。 - Jonathan Leffler
@JonathanLeffler:是的,我认为我们达成了一致。如果函数的预期行为是重定向标准输出,那就是一回事;但如果它还有其他功能,那么它不应该顺便重定向标准输出。 - ruakh
3个回答

24

exec是内置的Bash函数,因此它可以具有外部程序无法具备的特殊行为。特别地,它具有以下特殊行为:

如果未指定COMMAND,则任何重定向都会在当前shell中生效。

(这是从help exec给出的消息中引用的内容。)

这适用于任何类型的重定向;例如,您还可以编写以下任何一种:

exec >tmp.txt
exec >>stdout.log 2>>stderr.log
exec 2>&1

(但是,它不适用于管道。)


17

为什么这样做是历史的原因,没有一个很好的理由。

重定向操作符可以应用于任何程序(例如cat),>&形式被添加是为了表示“将文件描述符1复制到2”,因为它非常有用。 >&语法可能是因为特殊字符已经用尽,>&在基本含义上与&>相反,但具体情况不明确。所有这些都可以追溯到约1977年早期的Bourne shell。

为什么使用exec加上重定向来改变当前shell的输入和输出?可能是因为空命令> path已经有了相同的效果,它比cat /dev/null > path更容易输入,而当你的电传打字机最好只能以每秒10个字符的速度运行时,这一点很重要。因此,exec内置程序就被重载了:没有参数时,它会将重定向操作应用于自身。

由于bash尽可能遵循Bourne shell的约定,因此您会得到这些古董,正如您所怀疑的那样,您必须记住它们,特别是如果您试图给其他适当性别的成员留下深刻印象(即“妹子们很喜欢懂得I/O重定向奥秘的人”)。


4
“Chicks dig ...”的意思是“女孩喜欢...”,而“Ye Optimist!”表示肯定或赞同的语气。 - Jonathan Leffler
5
你的最后一句话很棒。显然,没有什么比深入了解Bash更具吸引力。 - tandrewnichols

3

原始来源:http://tldp.org/LDP/abs/html/x17784.html

exec <filename 命令将标准输入重定向到一个文件。从此以后,所有的标准输入都来自该文件,而不是它的正常来源(通常是键盘输入)。这提供了一种逐行读取文件并可能使用sed和/或awk解析每行输入的方法。

类似地,exec >filename 命令将标准输出重定向到指定的文件。这会将所有本来应该发送到标准输出的命令输出发送到该文件。

注意,exec N > filename 影响整个脚本或当前shell。从那时起,脚本或shell的PID的重定向已经改变。然而,N > filename 只影响新分派的进程,而不影响整个脚本或shell。

更多相关阅读可以在http://tldp.org/LDP/abs/html/io-redirection.html找到。有许多巧妙的小技巧可供使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接