这些重定向和文件描述符的目的是什么?

4
我看到了以下shell脚本。我认为我基本上知道它在做什么,但我仍然不明白为什么要使用这么多的重定向和文件描述符?例如,exec 3>&1do something 2>&1 1>&3exec 3>&-的目的是什么。
#-Open file descriptor (fd)
exec 3>&1

#-Create a form and then store data to $VALUES variable
VALUES=$(dialog \
    --keep-tite \
    --ok-label "Submit" \
    --backtitle "Linux User Managment" \
    --title "Useradd" \
    --form "Create a new user" \
    15 50 0 \
    "Username:" 1 1 "$user"     1 10 10 0 \
    "Shell:"    2 1 "$shell"    2 10 15 0 \
    "Group:"    3 1 "$groups"   3 10 8 0 \
    "HOME:"     4 1 "$home"     4 10 40 0 \
2>&1 1>&3)

# close fd
exec 3>&-

# display values just entered
echo "$VALUES"

能否告诉我为什么它们是必要的?是因为正在使用的dialog工具吗?我问这个问题是因为我从未见过人们在简单命令(如ls等)中这样做。

exec 3>&1
ls 2>&1 1>&3
exec 3>&-
2个回答

6
通常,dialog通过标准输出(文件描述符1)向用户显示对话框,通过标准输入(文件描述符0)读取用户的按键,并将用户填写的值输出到标准错误(文件描述符2)。引入额外的文件描述符是为了通过$(command…)替换(与反引号相同)读取这些值。命令替换会获取内部命令(在本例中是dialog…)发送到其标准输出的内容,并将其填充到外部命令(在本例中是VALUES=…)中。 2>&1重定向使dialog将字段值发送到其标准输出中,从而可以将其捕获到VALUES中。因此,dialog需要一个不同的文件描述符来向用户显示对话框。exec 3>&1 复制了原始的标准输出文件描述符。也就是说,在执行该命令后,文件描述符3和文件描述符1指向同一个文件——原始的标准输出。1>&3重定向使dialog将其对话框显示到原始的标准输出上。
换句话说,引入文件描述符3的原因是为了暂时“保存”标准输出。

4
这个问题很简单:
exec 3>&1

任何写入文件描述符3的内容都将与文件描述符1,即标准输出,相同。

VALUES=$(command ...arguments... 2>&1 1>&3)

在这里,任何写入文件描述符2(标准错误)的内容都会和文件描述符1(标准输出)一样被处理。然而,标准输出的定义随后被更改,以便将任何写入标准输出的内容发送到文件描述符3相同的位置。这是在命令替换$(...)操作内部完成的,因此标准输出通常被捕获并保存在文件中。这意味着变量VALUES将存储命令向标准错误写入的任何内容,而原始标准输出将获取命令向标准输出写入的任何内容。
最后:
exec 3>&-

关闭文件描述符3;从此以后,试图对其进行写操作将失败。

您模拟该命令的步骤应为:

exec 3>&1
variable=$(ls 2>&1 1>&3)
exec 3>&-

这段代码能够在$variable中捕获来自ls的任何错误,并且同时允许您查看ls在标准输出中写入的任何内容。一般情况下不会使用这种方法,因为它的需求有些不寻常。


+1,尽管“简单”有点牵强 :) 你所说的“标准输出通常被捕获在文件中”,是指被捕获在一个变量中吗? - mklement0
“简单”是因人而异的;也许我指的是“相对简单但不完全明显”。我还在考虑使用“文件”还是“变量”;输出到文件描述符,这是某种类型的文件,然后从中读取数据(在某种类型的文件描述符上),读操作的结果保存到变量中。所以,“文件”和“变量”都是正确的。 - Jonathan Leffler

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