我正在寻找一个bash one-liner,它将stdin复制到stdout而不进行交错。到目前为止我找到的唯一解决方案是使用tee
,但这确实产生了交错输出。我的意思是:
如果是文件f
读取
a
b
我想执行
cat f | HERE_BE_COMMAND
获取
a
b
a
b
如果我使用tee -
作为命令,输出通常看起来像
a
a
b
b
有关清洁解决方案的任何建议吗?
澄清
cat f
命令只是输入来源的一个示例。实际上,它是一个可以(应该)只执行一次的命令。我还想避免使用临时文件,因为处理后的数据排序敏感,并且当执行的命令被中断时,临时文件总是容易出错。此外,我对涉及其他脚本(如上所述,它应该是单行)或需要在实际复制命令之前执行的预备命令的解决方案不感兴趣。
答案 0 :(得分:5)
<command_which_produces_output> | { a="$(</dev/stdin)"; echo "$a"; echo "$a"; }
通过这种方式,您可以在a
中保存标准输入中的内容(请选择更好的名称),然后再echo
两次。
注意$(</dev/stdin)
是一种类似但更有效的$(cat /dev/stdin)
方法。
以下列方式使用tee
:
<command_which_produces_output> | tee >(echo "$(</dev/stdin)")
在这里,您首先要写入标准输出(tee
执行的操作),还要写入process substitution创建的FIFO文件:
>(echo "$(</dev/stdin)")
例如,查看它在我的系统中创建的文件:
$ echo >(echo "$(</dev/stdin)")
/dev/fd/63
现在,echo "$(</dev/stdin)"
部分就是我发现在打印之前首先读取整个文件的方式。它echo
是从流程替换的标准输入中读取的内容,但是一旦读取了所有输入(不像逐行打印的cat
)。
答案 1 :(得分:2)
将第二个输入存储在临时文件中。
cat f | tee /tmp/showlater
cat /tmp/showlater
rm /tmp/showlater
更新: 如评论(@ j.a。)所示,上述解决方案需要根据OP的实际需求进行调整。在函数中调用会更容易,你想用初始命令和tee / cat / rm中的错误做什么?
答案 2 :(得分:0)
我找到的一个可能的解决方案是以下awk
命令:
awk '{d[NR] = $0} END {for (i=1;i<=NR;i++) print d[i]; for (i=1;i<=NR;i++) print d[i]}'
然而,我觉得必须有更多的规范&#34;这样做的方式。
答案 3 :(得分:0)
一个简单的bash脚本? 但是这将存储所有stdin,为什么不将输出存储到文件中,如果需要则读取文件?
full=""
while read line
do
echo "$line"
full="$full$line\n"
done
printf $full
答案 4 :(得分:0)
最好的方法是将输出存储在文件中并稍后显示。使用tee
具有显示输出的优势:
if tmpfile=$(mktemp); then
commands | tee "$tmpfile"
cat "$tmpfile"
rm "$tmpfile"
else
echo "Error creating temporary file" >&2
exit 1
fi
如果输出量有限,您可以这样做:
output=$(commands); echo "$output$output"