如何转换为大写 stderr 输出而不是 stdout?

如何转换为大写 stderr 输出而不是 stdout?

我正在使用 rsync 备份一些文件:

rsync -PaSh --stats --delete -e "-i key -p XXXX" "/source/" [email protected]:/destination/ 2> output.txt | grep -e 'bytes  received' -e 'total bytes' -e files -e 'total file size:' >> output.txt

因为有数千个文件,我只想查看任何错误和最后的摘要。

上面的命令输出如下:

rsync: delete_file: unlink(test/test.txt) failed: Permission denied (13)
Number of files: 12 (reg: 10, dir: 2)
Number of created files: 0
Number of regular files transferred: 0
sent 382 bytes  received 137 bytes  41.52 bytes/sec

我只想将任何错误转换为大写(以引起注意)并保持摘要不变。

所以它看起来像这样:

RSYNC: DELETE_FILE: UNLINK(TEST/TEST.TXT) FAILED: PERMISSION DENIED (13)
Number of files: 12 (reg: 10, dir: 2)
Number of created files: 0
Number of regular files transferred: 0
sent 382 bytes  received 137 bytes  41.52 bytes/sec

我怎样才能实现这个目标?

谢谢

答案1

您可以有效地交换标准输入标准输出借助临时文件描述符(此处为 fd 3):

cmd 3>&2 2>&1 1>&3- | tr '[:lower:]' '[:upper]'

那就是“将新的 fd 指向该位置标准错误指向、指向标准错误在哪里标准输出点,点标准输出去哪里标准错误最初指出“......简单,对吧?:)

或者换句话说:现在标准错误来自cmd将像这样穿过管道标准输出而原来的标准输出已被重定向到标准错误。该tr命令将进行大写转换。

更新:尽管您接受了上面的答案,但您的愿望清单包括操纵的能力标准输出标准错误同时地。因此,让我们尝试解决这个问题......请记住,我们会遇到一些我不经常做的事情!

一个简单的交换标准输出/标准错误不会做任何有用的事情。无论有没有交换,您都无法通过单个管道使用两个不同的流。作为替代方案,我首先想到的是使用 FIFO(命名管道):

mkfifo /tmp/fifo1 /tmp/fifo2

# run the key command in the background, in a subshell to suppress
# job control messages (e.g. "[1] 12345" and "[1]+ Exit ...")
( cmd > /tmp/fifo1 2> /tmp/fifo2 & )

# concatenate tr/stderr and grep/stdout using process substitution
# (I'm assuming the summary information occurs at the end of rsync output)
cat <(cat /tmp/fifo2 | tr '[:lower:]' '[:upper:]') <(grep ... /tmp/fifo1) 

rm -f /tmp/fifo1 /tmp/fifo2

如果愿意的话,您实际上可以将所有这些都放在一行上!

mkfifo /tmp/fifo1 /tmp/fifo2; (cmd > /tmp/fifo1 2> /tmp/fifo2 &); cat <(cat /tmp/fifo2 | tr '[:lower:]' '[:upper:]') <(grep ... /tmp/fifo1); rm -f /tmp/fifo1 /tmp/fifo2

我的健全性检查工作正常,所以请尝试一下。

答案2

要将 stderr 转换为大写而不更改 stdout 和 stderr 的位置:

{ rsync ... 2>&1 >&3 3>&- | perl -Mopen=locale -pe '$_=uc' >&2 3>&-; } 3>&1

这是将原始 stdout 复制到 fd 3 上,因此我们可以将其恢复为rsync.

这里使用perl而不是因为它可以为-> (使用 GNU )或-> (使用 GNU tr/sed/awk )tr等提供更好的结果。StéphaneSTÉPHANESTéPHANEtrtrafficTRAFFICTRAffiC

请注意,现在 stderr 通过管道,这可能会影响 stdout 和 stderr 消息的相对顺序,因为 stderr 消息现在被延迟。

对于您可能会发现有用的其他一些方法。

答案3

使用下面的命令代替您的命令。将错误重定向到 output.txt 后,我​​添加了一个额外的命令

我添加了 sed -i "s/.*/\U&/g" output.txt
经测试其工作正常


rsync -PaSh --stats --delete -e "-i key -p XXXX" "/source/" [email protected]:/destination/ 2> output.txt ;sed -i  "s/.*/\U&/g" output.txt| grep -e 'bytes  received' -e 'total bytes' -e files -e 'total file size:' >> output.txt  

相关内容