假设我有一个脚本,我想通过管道传输到另一个命令或重定向到一个文件(sh
在示例中通过管道传输到)。假设我正在使用 bash。
我可以使用echo
:
echo "touch somefile
echo foo > somefile" | sh
我也可以使用以下方法做几乎相同的事情cat
:
cat << EOF
touch somefile
echo foo > somefile
EOF
但如果我用“EOF | sh”替换“EOF”,它只是认为它是heredoc的一部分。
我怎样才能cat
从标准输入输出文本,然后通过管道将其传输到任意位置?
答案1
有多种方法可以做到这一点。最简单的可能是这样的:
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 和 echo 很简单。表示
cat <&3
使用从 fd 3 重定向的文件描述符 (fd) 0 (stdin) 运行 cat;换句话说,cat out 来自 fd 3 的输入。 - 在
(...)
启动之前,shell 会看到这两个文档重定向,并用管道的读取端替换 fd 0 (<<EOF
) 和 fd 3 ( )3<<EOF2
- 一旦启动初始命令,shell 就会读取其标准输入,直到达到 EOF 并将其发送到第一个管道的写入端
- 接下来,它对 EOF2 和第二个管道的写入端执行相同的操作
答案2
我只是想指出 usingmeow
与 一样有效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!
的内容是这里的文档。meow
是结束标记这里的文档。内容通过使用>>
附加到cat
。
通过管道传输到标准输出和文件:
要完成您要求的管道,不这里的文档是必须的。
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
答案3
我想为此添加一个变体,这对我处理需要通过管道运行元素列表到循环的情况很有用while
:
cat <<EOF | while read -r FOO; do
bar
baz
quux
EOF
echo $FOO
done
也可以不带猫来写
while read -r FOO; do
echo $FOO
done <<EOF
bar
baz
quux
EOF