26

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

Wesley
  • 14,263

3 Answers3

33

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 07: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 04 '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 'SO- stop being evil' Oct 04 '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
Devdas
  • 181
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.

brodie31k
  • 131