我正在学习 bash 重定向。我希望下面的代码能够完成与ls | grep foo | grep bar
.
#!/bin/bash
{
{
ls | grep foo
} 2>&1 1>&4 | grep bar
} 4>&1
这匹配 foo 但不匹配 foo 和 bar。我认为这会起作用,因为将2>&1
fd 1 中的管道复制到 fd 2,然后我们将 fd 1 重置为标准输出。
您可以在保留大括号(上下文)的同时修复此代码吗?如果我删除2>&1 1>&4
它,它会按预期工作。但我想学习。
我认为在管道的左侧|它只需要 stdout,所以即使我将管道复制到 fd 2,它仍然只会在管道的左侧查找 fd 1。
参考:https://wiki.bash-hackers.org/howto/redirection_tutorial#an_example
在上面引用的链接中,有一个图表,其中 cmd1 的 fd 2 指向 cmd3 的 fd 0。我正在尝试用我的例子来验证这一点。
答案1
你的尝试:
{
{
ls | grep foo # goes to stdout (fd 1)
} 2>&1 1>&4 | grep bar # at this level: 2 now points to where fd1 is pointing (stdout), and 1 is *then* directed to the new fd 4 (ie to stdin of the outside curly)
} 4>&1 ## at this shell 'level', a new fd 4 is now pointing to where 1 is pointing: stdout
:因此 grep 栏仅在 { ls | 的 stderr 上完成grep foo },因此在一个空的标准输入上,作为 { ls | 的唯一标准错误grep foo } 转到 { ls | grep foo } 的标准输出grep foo }.这永远不会看到文件名。 ths 文件名转到 fd 4 尝试:
{
{
ls | grep foo
} 2>&1 1>&4
} 4>&1 | grep bar
或者
{
{
ls | grep foo
} 2>&1 1>&4 | <&4 grep bar
} 4>&1
并比较...
注意:如果您想让内部命令的 stderr 也转到 stdout,则需要将其复制到第二个位置: 1>&4 2>&1 [即:1 现在转到 fd 4,然后 2 转到 1 所在的位置现在指向,即 fd 4 以及]
答案2
据我所知,以下情况属实。
这
{
{
ls | grep foo
} 2>&1 1>&4 | grep bar
} 4>&1
相当于
(ls | grep foo 2>&1 1>&4 | grep bar) 4>&1
它会失败,因为 fd 4 是 /dev/pts/0,而 1>&4 将导致 fd 1 具有相同的 /dev/pts/0 而不是管道。
答案3
看来您希望重定向来复制数据?考虑使用tee
.当你学习的时候,我不会说更多破坏事情的。
也可用于shellcheck
检查您的代码。它将帮助您更快地找到大多数错误。