Yogeshwer Sharma
Yogeshwer Sharma

Reputation: 3837

bash: how to intercept every command

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: 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}/'

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:

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

Upvotes: 12

Views: 6719

Answers (5)

Holloway
Holloway

Reputation: 7367

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.)

Upvotes: 5

xeor
xeor

Reputation: 5455

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

Upvotes: 3

Michał Šrajer
Michał Šrajer

Reputation: 31182

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

Upvotes: 10

Keith Thompson
Keith Thompson

Reputation: 263217

$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.

Upvotes: 4

sauce
sauce

Reputation: 592

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.

Upvotes: 1

Related Questions