我如何将给出的每个命令传送给 shell?

我如何将给出的每个命令传送给 shell?

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

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

我做过类似的事情,但不完全是:

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

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

其主要目的是娱乐/学习。

答案1

你可以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!

但是,这之后仍会执行该命令。感谢伊尔卡楚我找到了一种解决方法:

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

答案2

您可以稍微调整一下方法。不要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。printf比 更可靠、更安全echo

相关内容