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

str*_*gee 101 shell io-redirection cat here-document

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

我可以使用echo

echo "touch somefile
echo foo > somefile" | sh
Run Code Online (Sandbox Code Playgroud)

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

cat << EOF
touch somefile
echo foo > somefile
EOF
Run Code Online (Sandbox Code Playgroud)

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

我怎样才能使它cat从标准输入输出文本,然后将其通过管道传输到任意位置?

ash*_*ash 168

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

cat <<EOF | sh
touch somefile
echo foo > somefile
EOF
Run Code Online (Sandbox Code Playgroud)

另一个,在我看来是更好的语法:

(
cat <<EOF
touch somefile
echo foo > somefile
EOF
) | sh
Run Code Online (Sandbox Code Playgroud)

这也有效,但没有子shell:

{
cat <<EOF
touch somefile
echo foo > somefile
EOF
} | sh
Run Code Online (Sandbox Code Playgroud)

更多变化:

cat <<EOF |
touch somefile
echo foo > somefile
EOF
  sh
Run Code Online (Sandbox Code Playgroud)

或者:

{ cat | sh; } << EOF
touch somefile
echo foo > somefile
EOF
Run Code Online (Sandbox Code Playgroud)

顺便说一句,我希望cat在您的问题中使用 是其他内容的占位符。如果没有,把它拿出来,像这样:

sh <<EOF
touch somefile
echo foo > somefile
EOF
Run Code Online (Sandbox Code Playgroud)

这可以简化为:

sh -c 'touch somefile; echo foo > somefile'
Run Code Online (Sandbox Code Playgroud)

或者:

sh -c 'touch somefile
echo foo > somefile'
Run Code Online (Sandbox Code Playgroud)

重定向输出而不是管道

sh >out <<EOF
touch somefile
echo foo > somefile
EOF
Run Code Online (Sandbox Code Playgroud)

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

cat >out <<EOF
test
EOF
Run Code Online (Sandbox Code Playgroud)

多个此处文档

( cat; echo ---; cat <&3 ) <<EOF 3<<EOF2
hi
EOF
there
EOF2
Run Code Online (Sandbox Code Playgroud)

这会产生输出:

hi
---
there
Run Code Online (Sandbox Code Playgroud)

这是发生了什么:

  • shell( ... )在子shell 中看到并运行包含的命令。
  • cat 和 echo 很简单。该cat <&3说与文件描述符运行cat(FD)0(标准输入)从FD 3重定向; 换句话说,从 fd 3 中取出输入。
  • (...)启动之前,shell 看到两个 here 文档重定向并用管道的读取端替换 fd 0 ( <<EOF) 和 fd 3 ( 3<<EOF2)
  • 一旦启动了初始命令,shell 就会读取它的 stdin 直到到达 EOF 并将其发送到第一个管道的写端
  • 接下来,它对 EOF2 和第二个管道的写入端执行相同的操作

  • 它可能有助于理解 shell 如何处理它。当它评估命令行并找到 &lt;&lt;EOF 时,它会从标准输入中读取,直到找到仅包含 EOF 的行或输入结束。原始命令行上尚未处理的所有其他内容将继续处理。因此,例如,可以执行如下操作:`(cat; echo ---; exec &lt;&amp;3; cat) &lt;&lt;EOF 3&lt;&lt;EOF2 &gt;out`,然后使用两个此处块给出该命令输入一排。 (2认同)

Ale*_*der 5

我只是想指出 usingmeow与 一样有效EOF

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

#!/bin/sh
cat <<meow>> cat
Meow!
meow
Run Code Online (Sandbox Code Playgroud)

另存为cats并使用 使其可执行chmod +x cats,然后使用以下命令运行它./cats

$ ./cats
$ cat cat
Meow!
$ ./cats
$ cat cat
Meow!
Meow!
Run Code Online (Sandbox Code Playgroud)

解释:

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

通过管道传输到标准输出和文件:

要进行您要求的管道安装,不需要此处的文件。

cat不能同时输出文本和传递文本,但tee它完全符合您的要求:

echo echo | tee tee
Run Code Online (Sandbox Code Playgroud)

这将输出字符串echo并写入echo名为tee.

cat如果这是要求的一部分,您还可以通过以下方式传递输出:

echo echo | tee tee | cat </dev/stdin
Run Code Online (Sandbox Code Playgroud)

要不就:

echo echo | tee tee | cat
Run Code Online (Sandbox Code Playgroud)

文件内容:

$ cat tee
echo
Run Code Online (Sandbox Code Playgroud)

  • @strugee,当同一个 fd 被重定向多次时,“&gt;”可以在“zsh”中创建管道,如“echo foo &gt;&amp;1 &gt; tee”或“echo foo &gt; tee |”。cat`,其中`zsh`实现了一个内部`tee`,将`echo`的输出提供给`cat`和`tee`文件。 (2认同)