user1595858
user1595858

Reputation: 3890

combine find and grep into a single command

How to combine below two into one line without changing the first one?

 # find / -name sshd_config -print
 # grep -I <sshd_config path>  permitrootlogin

I came up with the following, but don't know whether I gives correct result in different cases

cat `find / -name sshd_config -print` |grep permitrootlogin

Upvotes: 0

Views: 2737

Answers (4)

aallrd
aallrd

Reputation: 116

You could do something like that:

find / -name "somefilename" -print0 | xargs -0 grep "something"

The 'xargs' keyword will transform the stdout into arguments that can be read by grep.

Upvotes: 3

das-g
das-g

Reputation: 9994

I guess what you want is use the output of find / -name sshd_config -print (which should be the path of the sshd_config file) and use it as the second argument to grep (so that that the sshd_config file gets parsed for your search string).

There are several ways to achieve this.

Commands in back-quotes (`) are replaced by their output. So

grep permitrootlogin `find / -name sshd_config -print`

will be replaced by

grep permitrootlogin /path/to/the/sshd_config

which will search /path/to/the/sshd_config for permitrootlogin.

The same happens with

grep permitrootlogin $(find / -name sshd_config -print)

As another answer already mentions, this syntax has some advantages over the back-ticks. Namely, it can be nested.

However, this still runs into a problem when the path where the file is found contains spaces. As both backticks and $(...) just perform text substitution, such a patch would be passed as several arguments to grep, each probably being an invalid path. (/path/to the/sshd_config would become /path/to and the/sshd_config.)

Rather than working around this with fancy quoting and escaping strategies, remember that UNIX commands were already designed for being used in combination, usually by pipes. Indeed find has a -print0 action which will separate paths of found files by \0, so that they can be distinguished from paths containing whitespace. Alas, grep can't process a zero-delimited list of files and still wants the files to search as invocation arguments, not on stdin.

This is where xargs comes into play. It applies stuff it gets on stdin as arguments to other commands. And with its -0 option, it interprets stdin as a zero-delimited list instead of treating whitespace as delimiters.

So

find / -name sshd_config -print0 | xargs -0 grep permitrootlogin

should have you covered.

Upvotes: 0

Charles Duffy
Charles Duffy

Reputation: 295815

Don't do cat $(...) [$() is the modern replacement for backticks] -- that doesn't work reliably if your filenames contain special characters (spaces, wildcards, etc).

Instead, tell find to invoke cat for you, with as many filenames passed to each cat invocation as possible:

find / -name sshd_config -exec cat -- '{}' + | grep permitrootlogin

...or, even better, ignore cat altogether and just pass the filenames to grep literally:

find / -name sshd_config -exec grep -h -e permitrootlogin -- /dev/null '{}' +

Replace the -h with -H if you want filenames to be shown.

Upvotes: 6

Slaaavo
Slaaavo

Reputation: 112

| is a pipeline, which means, that the standard output of catfind / -name sshd_config -print`` will go to standard intput of grep permitrootlogin, so you just have to be sure what's the output of the first command

Upvotes: -1

Related Questions