如何将输出重定向与here-document和cat结合使用?


56

假设我有一个脚本,该脚本想通过管道传递到另一个命令或重定向到文件(sh示例使用管道)。假设我正在使用bash。

我可以使用echo

echo "touch somefile
echo foo > somefile" | sh

我也可以使用cat以下方法做几乎相同的事情:

cat << EOF
touch somefile
echo foo > somefile
EOF

但是,如果我将“ EOF”替换为“ EOF | sh”,它只是认为这是heredoc的一部分。

如何使它cat从stdin输出文本,然后将其通过管道传输到任意位置?


touch除非在那里,否则您到底想要什么?只是读取输入文件并使用stdout重定向到另一个文件?
拉胡尔·帕蒂尔

2
@RahulPatil当然没用。我只是想要一个包含多行代码的示例,以更好地说明heredoc。并查看示例使用echo-我想知道将使用什么等效方法cat
奋斗

您的示例是使用sh多个字符串创建脚本并将其直接传递给sh。我发现您的Q想要将多个命令(包括HERE文档)的文本输出直接传递给命令。Ash的答案的第二个示例就是这样做的。
戴夫X

Answers:


91

有多种方法可以做到这一点。最简单的可能是这样的:

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF

另一种,我认为这是更好的语法:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh

这也可以,但是没有子shell:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh

更多变化:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh

要么:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF

顺便说一句,我希望cat您在问题中使用占位符。如果没有,将其取出,像这样:

sh <<EOF
touch somefile
echo foo > somefile
EOF

可以简化为:

sh -c 'touch somefile; echo foo > somefile'

要么:

sh -c 'touch somefile
echo foo > somefile'

重定向输出而不是管道

sh >out <<EOF
touch somefile
echo foo > somefile
EOF

使用cat得到相当于echo test > out

cat >out <<EOF
test
EOF

多个此处文档

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2

产生输出:

hi
---
there

这是怎么回事:

  • Shell会看到( ... )并在子Shell中运行附带的命令。
  • 猫和回声很简单。从cat <&3文件3重定向到文件描述符(fd)0(stdin)的cat运行;换句话说,找出fd 3的输入。
  • (...)开始运行之前,shell会看到这里的两个文档重定向,并用管道的读取端替换了fd 0(<<EOF)和fd 3(3<<EOF2)。
  • 启动初始命令后,shell会读取其stdin直到达到EOF并将其发送到第一个管道的写端
  • 接下来,它对EOF2和第二个管道的写端执行相同操作

给出倒数第二个示例,您可以举一个使用stdout重定向代替管道的示例吗?
奋斗

我用重定向示例编辑了答案。这是您要编辑的表格吗?如果没有,您可以只提供该部分的第一行来说明吗?
2013年

1
了解外壳如何处理此过程可能会有所帮助。当它评估命令行并找到<<< EOF时,它将从标准输入中读取,直到找到仅包含EOF的行或输入结束为止。原始命令行上尚未处理的所有其他内容,将继续处理。因此,例如,可以执行以下操作:(cat; echo ---; exec <&3; cat) <<EOF 3<<EOF2 >out然后在命令输入中连续添加两个here-block。
灰烬

您对shell处理的解释很有趣,但令我头疼:)我想知道的是,使用heredoc cat等效于什么echo test > out。而给定的示例在管道末端添加了重定向。
13年

1
@OlivierDulac-我在答案中添加了多个Heredoc示例。
2013年

1

我只想指出使用meow和一样有效EOF

该脚本将追加Meow!到名为的文件中cat

#!/bin/sh
cat <<meow>> cat
Meow!
meow

另存为cats并使用使其可执行chmod +x cats,然后使用./cats

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!

说明:

  • cat <<meow此处文档的语法。它指示脚本拾取此行之后的文本块,直到遇到字符串为止meow。然后将输出内容(或通过管道传递)。
  • >> cat通过管道传输到名为的文件cat
  • 使用>而不是>>将覆盖文件而不是附加到文件。
  • Meow!here文档的内容。
  • meowhere文档的结束标记。使用将内容>>附加到cat

管道连接到stdout和文件:

要进行您要求的管道输送,不需要此处的文件

cat不能同时输出文本和传递文本,但是tee与您的要求完全匹配:

echo echo | tee tee

这将同时输出字符串echo并写入echo名为的文件tee

cat如果这是要求的一部分,您也可以通过输出:

echo echo | tee tee | cat </dev/stdin

要不就:

echo echo | tee tee | cat

文件内容:

$ cat tee
echo

1
这并不能真正回答问题。也>不会像您的最后一个项目符号所示那样创建管道。
奋斗

2
@strugee,>可以在创建管zsh时相同的fd被重定向几次如在echo foo >&1 > teeecho foo > tee | cat,其中zsh实现了一个内部tee馈送的输出echo到两个cattee文件。
斯特凡Chazelas

更新了我的答案以更好地回答问题。
亚历山大
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.