![我如何将给出的每个命令传送给 shell?](https://linux22.com/image/1152108/%E6%88%91%E5%A6%82%E4%BD%95%E5%B0%86%E7%BB%99%E5%87%BA%E7%9A%84%E6%AF%8F%E4%B8%AA%E5%91%BD%E4%BB%A4%E4%BC%A0%E9%80%81%E7%BB%99%20shell%EF%BC%9F.png)
我想编辑我的 .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
。