For the better part
of my career I used 'find' incorrectly, or at the very least very
naively. The '-exec' trickery eluded me for over a decade;
I often relied on running child processes or _worse_ saving results to a file to run subsequent command on.
For instance, if I wanted to examine log files that had 'error' in it, I'd fashion a command to open VI with the arguments of the result from a gr
ep command;
e.g. $ vi `grep -li error *.log`
The command line
would first execute the grep command, the results formed the arguments
to the vi command. Alternatively, I'd very occasionally
use xargs as an
alternative. Alternatively, to the alternative, I'd run the equivalent
of the grep command and redirect the output to a file, then 'cat' the file contents as arguments to whatever command I wanted.
e.g.
$ grep -li error *.log > files.txt
$ vi `cat files.txt`
Clumsy, clumsier and often times clumsiest. But, lacking an understanding of the '-exec' option, it was what I knew, got me where I needed to be, but was a source of embarrasement for someone who used Linux professionally for years.
Then, about 8 years ago, I spent some time familiarizing myself with '-exec' and everyday tasks got a bit easier. These past days I've been spending time on chaining '-exec' commands, something I wasn't familar with until recently.
Let's say you are asked to search a server for scripts that use 'ftp', not 'sftp', as a security audit. A whole lotta scripts exist that use neither, a subset of them using ftp/sftp, and a subset of that subset exclusively use ftp (our desired file list). An approach would be to first find all scripts that reference 'ftp', then filter out the ones that use 'sftp'.
$ find /src/scripts/ -type f -exec grep -l 'sftp' {} \; #-- finds scripts referencing sftp
$ grep -L 'sftp' [filelist]; #--lists files w/o sftp expression
You want to feed the results of the first command as arguments to the second command. A clumsy approach (the one I used for years) would be:
$ grep -L 'sftp' `find /src/scripts/ -type f -exec grep -l 'ftp' {} \;`
But, the equivalent can be accomplished by chaining '-exec' commands in a single command.
$ find /src/scripts/ -type f -exec grep -l 'ftp' {} \; -exec grep -L sftp {} \;
Chained exec commands are executed left-to-right, each executed as child commands. Subsequent '-exec' commands are only executed on files/lines that satisfy the previous '-exec' command. So, 'grep -L sftp...' is only run on the results of the previous command (e.g. "grep -l 'ftp'...). The end results is first finding all files containing 'ftp', then finding files that don't contain 'sftp'. The output of both '-exec' commands, each on seperate lines, which can be confusing. We can suppress the output from the first command by specifying '-quiet (or -q)' to the first grep command, as follows:
$ find /src/scripts/ -type f -exec grep -lq 'ftp' {} \; -exec grep -L sftp {} \;
Now, the resulting file list from the first exec is still passed to the subsequent exec and the output to stdout is representative of only the second command.
No comments:
Post a Comment