开发者

bash: how to intercept every command

开发者 https://www.devze.com 2023-03-25 05:28 出处:网络
Is there a way to intercept every command given to bash? I can intercept a particular command, e.g., cd by defining a function cd() and I can do that for one-command-at-a-time for other commands as we

Is there a way to intercept every command given to bash? I can intercept a particular command, e.g., cd by defining a function cd() and I can do that for one-command-at-a-time for other commands as well. But can I write a function which gets called before every command is executed? I want to do some bookkeeping of commands, and then executed the command.

Michał Šrajer's idea PS4='$(echo $(date) $(history 1) >> /tmp/trace.txt) TRACE: ' looks very promising but here is the output I get:

$ 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: ic开发者_StackOverflow中文版mp_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}/'

And Wed Aug 3 12:47:27 PDT 2011 6672 ping www.google.com get written in /tmp/trace.txt exactly 5 times. The four other ones comes from my definition of PS1 where I run the following command: $(git branch 2> /dev/null | grep -e "\* " | sed "s/^..\(.*\)/ {\1}/"). Two questions:

  • Is it possible to write the command to /tmp/trace.txt exactly?
  • And more importantly, is it possible to not clutter the output of the command, but only write the command to /tmp/trace.txt?

I am so excited about the possibility of being able to record commands from all my bash sessions in one place!


You can set the PS4 variable, which is evaluated for every command being executed just before the execution if trace is on:

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

Then, enable trace:

set -x

To stop tracing, just:

set +x


In case anyone finds this question through Google, I solved this by adding the following to my ~/.bashrc.

PROMPT_COMMAND='echo "$(date +"%Y/%m/%d (%H:%M)") $(history 1 |cut -c 7-)" >> /tmp/trace'
export PROMPT_COMMAND

This results in /tmp/trace having contents such as

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 is executed after every command that is run through bash
  • $(date +"%Y/%m/%d (%H:%M)") prints the date and time
  • $(history 1 |cut -c 7-) prints the command
    • cut -c 7- removes the number that history would otherwise include
  • >> /tmp/trace appends the complete string to the file you specify. (I'd advise against anything in /tmp/ unless you want it to be deleted when you restart the computer.)


$PROMPT_COMMAND, if set, contains a command to execute before printing the prompt ($PS1). Set it to the name of a function that captures the output of history 1.


You can use trap with DEBUG to do this, like trap 'a oneliner in here' DEBUG.


Not sure about intercepting every command but in some versions of Linux every command gets logged to ~/.bash_history. You could either figure out how that works or just parse that file to see the last command.

0

精彩评论

暂无评论...
验证码 换一张
取 消