如何通过管道传递给 shell 的每个命令?

M. *_*rra 14 command-line bash bashrc

我想编辑我的 .bashrc 以便在 shell 上执行的每个命令都通过管道传输到某些东西,例如:

 $ sudo apt update
  _________________
< sudo apt update >
 -----------------
    \   ^__^
     \  (oo)\_______
        (__)\       )\/\
            ||----w |
            ||     ||
Run Code Online (Sandbox Code Playgroud)

我已经管理了一些相当相似的东西,但不完全是:

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

这不是想要的结果,因为它只在退出当前 shell 后发生。

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

des*_*ert 16

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

trap 'bash -c "$BASH_COMMAND" | cowsay' DEBUG
Run Code Online (Sandbox Code Playgroud)

示例运行

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

但是,这之后仍会执行命令。感谢ilkkachu我找到了解决方法:

$ shopt -s extdebug
$ trap 'bash -c "$BASH_COMMAND" | cowsay; false' DEBUG
$ echo "AU is awesome!"
 __________________
< AU is awesome! >
 ------------------
        \   ^__^
         \  (oo)\_______
            (__)\       )\/\
                ||----w |
                ||     ||
Run Code Online (Sandbox Code Playgroud)


mur*_*uru 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"'
Run Code Online (Sandbox Code Playgroud)

在这里,我使用的是 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 |
                ||     ||
Run Code Online (Sandbox Code Playgroud)

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

假设您已经知道是什么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。printf比 更可靠、更安全echo