如何通过管道将每个命令传递给外壳?


14

我想编辑我的.bashrc,以便将外壳程序上执行的每个命令通过管道传递给某些内容,例如:

 $ sudo apt update
  _________________
< sudo apt update >
 -----------------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||

我已经完成了一些类似的工作,但并不完全是:

$ bash
$ exec > >(cowsay)
$ echo "Hello AU!"
$ exit
 _______
< Hello AU! >
 -------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||

这不是期望的结果,因为它仅在退出当前shell之后发生。

主要用于娱乐/学习目的。


使用-n标志到cowsay很有用;它使其保留空白。
wjandrea

Answers:


12

您可以稍微调整一下方法。而不是cowsay直接传递给管道,而是读取输出直到一个定界字符,将该输出发送给cowsay,然后在每个命令之后打印该字符:

exec > >(while IFS= read -d '' -r line; do if [[ -n $line ]]; then echo; printf "%s\n" "$line" | cowsay; fi; done)
PROMPT_COMMAND='printf "\0"'

在这里,我使用的是ASCII NUL字符。您可以使用不太可能出现在命令输出中的其他内容。

这将在提示后打印,因此输出将很丑陋:

$ export LC_ALL=C
$ exec > >(while IFS= read -d '' -r line; do if [[ -n $line ]]; then echo; printf "%s\n" "$line" | cowsay; fi; done)
$ PROMPT_COMMAND='printf "\0"'
$ ls
$
 ______________________________________
/ Desktop Documents Downloads Music    \
| Pictures Public Templates Videos
\ examples.desktop                     /
 --------------------------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

$ echo foo
$
 ______
< foo  >
 ------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||

请注意,这将破坏任何尝试进行复杂输出或具有文本用户界面的命令(请考虑命令行编辑器,寻呼机等)。

假设您已经知道该怎么exec > >(...)做,流程替换中的部分是:

  • while IFS= read -d '' -r line; do ... done:这是读取ASCII NUL字符分隔的数据的相当普遍的习惯用法:

    • IFS= 将IFS设置为空字符串,这将禁用字段拆分
    • -r防止对输入进行特殊read处理\\n例如,将其读取为\n而不转换为换行符)。
    • -d ''是告诉read阅读直到NUL字符的方式

    因此,整个过程在NUL分隔的部分中循环输入,同时尽可能多地保留输入的内容。

  • if [[ -n $line ]]; then ... fi; done -仅当到目前为止读取的输入不为空时才采取措施。
  • echo; printf "%s\n" "$line" | cowsay;-打印前导空行,以使Cowsay输出与提示不冲突,然后将读取的输入发送到Cowsay。printfecho。更加可靠和安全。

1
由于我的提示中包含换行符,因此Cowsay输出确实与其中的第二部分发生冲突–也许还可以将提示设置为无干扰的内容?
甜点

16

您可以trap滥用bash的DEBUG信号:

trap 'bash -c "$BASH_COMMAND" | cowsay' DEBUG

运行示例

$ trap 'bash -c "$BASH_COMMAND" | cowsay' DEBUG
$ echo "AU is awesome!"
 __________________
< AU is awesome! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
AU is awesome!

但是,此后仍将执行命令。感谢ilkkachu,我找到了解决该问题的方法:

$ shopt -s extdebug
$ trap 'bash -c "$BASH_COMMAND" | cowsay; false' DEBUG
$ echo "AU is awesome!"
 __________________
< AU is awesome! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.