Bash:如何拦截每个命令

12
有没有办法拦截每个给予 bash 的命令?我可以通过定义一个函数 cd() 来拦截特定的命令,例如 cd,并且我也可以为其他命令一次拦截一个命令。但是我是否可以编写一个在每个命令执行之前调用的函数?我想对命令进行一些簿记,然后再执行命令。 Michał Šrajer 的想法 PS4='$(echo $(date) $(history 1) >> /tmp/trace.txt) TRACE: ' 看起来非常有前途,但我得到了以下输出:
$ ping www.google.com
 TRACE: ping www.google.com
PING www.l.google.com (74.125.224.52) 56(84) bytes of data.
64 bytes from 74.125.224.52: icmp_seq=1 ttl=56 time=3.77 ms
64 bytes from 74.125.224.52: icmp_seq=2 ttl=56 time=2.33 ms
^C
--- www.l.google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 2.334/3.054/3.774/0.720 ms
  TRACE: echo -ne '\033]0;myhost.com /home/yogeshwer/github/myproject\007'
  TRACE: grep -e '\* '
  TRACE: git branch
  TRACE: sed 's/^..\(.*\)/ {\1}/'

在 /tmp/trace.txt 中确切地写入了 5 次: Wed Aug 3 12:47:27 PDT 2011 6672 ping www.google.com, 其中另外四次来自我的 PS1 定义,其中我运行了以下命令: $(git branch 2> /dev/null | grep -e "\* " | sed "s/^..\(.*\)/ {\1}/")。两个问题:

  • 是否可能准确地将该命令写入到 /tmp/trace.txt 中?
  • 更重要的是,是否可能不混杂命令的输出,而只将命令写入到 /tmp/trace.txt 中?

我对能够在一个地方记录所有 bash 会话的命令的可能性感到非常兴奋!


“.bash_history” 不够满足您的需求,是吗? - Andrew
1
请注意,只有当 shell 退出时才会更新 .bash_history。 - Keith Thompson
.bash_history 不够用。PROMPT_COMMAND 在命令执行之前立即执行(我认为),但在 PROMPT_COMMAND 执行时我无法访问“即将执行的命令”。完美的解决方案是获取“即将执行的下一个命令”,对其进行一些统计(例如已执行多少次),并将其写入某个日志文件,然后再执行该命令。 - Yogeshwer Sharma
你不能删除额外的输出,PS4变量用于调试,这就是额外输出的来源。至于命令的多次出现,我认为这是因为|运算符在子shell中执行每个命令的原因。 - John Retallack
5个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
10

如果启用了跟踪(trace),则可以设置PS4变量,该变量在执行每个命令之前都会进行评估:

PS4='$(echo $(date) $(history 1) >> /tmp/trace.txt) TRACE: '

然后,启用跟踪:

set -x
停止跟踪,只需执行以下操作:
set +x

这听起来非常有前途。我已经编辑了问题(因为我发现在评论中写代码块很困难)。我已经接近成功,但无法弄清最后一步。 - Yogeshwer Sharma

5

如果有人通过谷歌找到这个问题,我解决了这个问题,方法是在我的~/.bashrc文件中添加以下内容。

PROMPT_COMMAND='echo "$(date +"%Y/%m/%d (%H:%M)") $(history 1 |cut -c 7-)" >> /tmp/trace'
export PROMPT_COMMAND
这将导致/tmp/trace具有以下内容:
2015/01/21 (14:34) pwd
2015/01/21 (14:36) less /tmp/trace
2015/01/21 (14:36) cd Documents
2015/01/21 (14:36) cd ..
2015/01/21 (14:36) ls -la
2015/01/21 (14:36) pwd
2015/01/21 (14:36) echo "helloWorld"
  • PROMPT_COMMAND 是在每次通过bash运行命令后执行的
  • $(date +"%Y/%m/%d (%H:%M)")打印日期和时间
  • $(history 1 |cut -c 7-) 打印命令
    • cut -c 7- 移除了原本包含在 history 中的数字
  • >> /tmp/trace将完整的字符串追加到您指定的文件中。(我建议不要使用/tmp/中的任何内容,除非您希望在重新启动计算机时删除它。)

4
如果设置了 $PROMPT_COMMAND,则在打印提示符($PS1)之前执行一个命令。将其设置为一个函数的名称,该函数捕获 history 1 的输出。

3
您可以使用DEBUG和trap来实现这一点,例如trap '在此输入一个简短的命令' DEBUG

1

不确定是否拦截每个命令,但在某些Linux版本中,每个命令都会被记录到~/.bash_history。您可以弄清楚它的工作原理,或者只需解析该文件以查看最后一个命令。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,