将stdin复制到stdout

时间:2015-10-20 10:09:38

标签: bash shell

我正在寻找一个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命令只是输入来源的一个示例。实际上,它是一个可以(应该)只执行一次的命令。我还想避免使用临时文件,因为处理后的数据排序敏感,并且当执行的命令被中断时,临时文件总是容易出错。此外,我对涉及其他脚本(如上所述,它应该是单行)或需要在实际复制命令之前执行的预备命令的解决方案不感兴趣。

5 个答案:

答案 0 :(得分:5)

解决方案1:

<command_which_produces_output> | { a="$(</dev/stdin)";  echo "$a"; echo "$a"; }

通过这种方式,您可以在a中保存标准输入中的内容(请选择更好的名称),然后再echo两次。

注意$(</dev/stdin)是一种类似但更有效的$(cat /dev/stdin)方法。

解决方案2:

以下列方式使用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"