19

I want to see all bash commands that have been run on a Linux server across multiple user accounts. The specific distribution I'm using is CentOS 5.7. Is there a way to globally search .bash_history files on a server or would it be a more home-grown process of locate | cat | grep? (I shudder just typing that out).

24

Use getent to enumerate the home directories.

getent passwd |
cut -d : -f 6 |
sed 's:$:/.bash_history:' |
xargs -d '\n' grep -s -H -e "$pattern" 

If your home directories are in a well-known location, it could be as simple as

grep -e "$pattern" /home/*/.bash_history

Of course, if a user uses a different shell or a different value of HISTFILE, this won't tell you much. Nor will this tell you about commands that weren't executed through a shell, or about aliases and functions and now-removed external commands that were in some user directory early in the user's $PATH. If what you want to know is what commands users have run, you need process accounting or some fancier auditing system; see Monitoring activity on my computer., How to check how long a process ran after it finished?.

  • +1 for suggesting process accounting instead. History files are really for user convenience and there are no simple ways to make them fool-proof enough for any sort of logging purposes. – jw013 Feb 15 '12 at 7:45
  • @jw013 Yes, I've already had my fill of how easy it is to edit / modify and otherwise muck with shell history. =| – Wesley Feb 15 '12 at 16:45
  • This is an old question, but it was my first google result, so maybe worth adding to. I modified this to check that the file exists before trying to grep it: getent passwd | cut -d : -f 6 | sed "s:$:/.bash_history:" | xargs -d'\n' -I{} sh -c "[ -f {} ] && echo {}" | xargs -d'\n' grep -Hn -e "$pattern" – BryKKan Oct 4 '17 at 21:03
  • 1
    @BryKKan Ignoring non-existent files is a good idea. Beware that the way you're doing it is dodgy: it should work in practice given that typical user names don't contain “weird” characters, but in general using {} like this is very dangerous. The file name is interpolated directly in the script. If you have a file name (here: a user name) containing, say, $(rm -rf /) or ;rm -rf /;, the command will be executed. Always pass file names as arguments to shell scripts, never use find or xargs's {} mechanism. – Gilles Oct 4 '17 at 21:13
4
find /home -name .bash_history | xargs grep <string>

Alternatively:

grep string $(find /home -name .bash_history)

Note that this covers home directories in default locations. It would be better to parse /etc/passwd or invoke getent, and parse the output of that.

for i in $(getent passwd | cut -d: -f6 ); do grep string ${i}/.bash_history; done
3

You could do

find /home | grep bash_history | xargs grep "whatever"

But I don't really think that is much better then what you were thinking.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.