Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

My desired outcome is the following: to recursively search a directory looking for a given string in all found files. The following command is my usual port of call:

find ./ | xargs grep -ns 'foobar'

However, when foobar has quotes the command fails and gives me a > prompt in the shell. The specific command that's causing the problem is as follows:

find ./ | xargs grep -ns 'add_action(\'save_post\','

I've tried to escape the quotes with backslashes but to no avail. What's the correct way to do this?

share|improve this question

3 Answers 3

up vote 6 down vote accepted

Single quotes are terminated by single quotes, all other characters in between (including backslashes) are ignored.

Suggestion: avoid find+xargs when grep -r pattern . can recursively grep on the current directory.

The below commands have equivalent behavior:

grep -rns "add_action('save_post'," .
grep -rns 'add_action('\'save_post\', .

The last command is interpreted as:

  1. 'add_action(' -> add_action(
  2. \' -> '
  3. save_post -> save_post
  4. \' -> '
  5. , -> ,

Concatenating these parts, the grep command receives the argument add_action('save_post',.

share|improve this answer
    
great insight on the interpretation, thanks! –  Matt Potts Apr 3 '12 at 10:19

xargs expects arguments quoted in some strange way that find doesn't produce. Never use xargs in combination with find, unless you know that your file names don't contain \"' or whitespace.

Instead of using xargs, let find directly call the program you want to run.

find . -exec grep -ns 'add_action('\''save_post'\'',' {} +

With exec … {} +, the program is invoked once for many files at once, like with xargs. Some older versions of find don't support + here¹, then you have to use ; instead, which invokes grep once per file.

You can alternatively use find … -print0 | xargs -0, if your utilities support it¹. The -print0 option tells find to emit names separated by a null byte, and -0 tells xargs to expect null-separated input and not to do any quote interpretation.

Note the quoting above: between single quotes, all characters are interpreted literally, except that ' signifies the end of the literal string. So '\'' is effectively a way of putting a literal single quote inside a single-quoted string; formally, it's “' end quote, \ literal ' single quote, ' begin quote”.

In the special case of grep, if your implementation supports it¹, you can dispense with find and use grep -r to search inside a directory recursively:

grep -r 'add_action('\''save_post'\'',' .

¹ Linux, Cygwin, FreeBSD and OSX support these features.

share|improve this answer
    
Thanks for the info about -print0 and -0, I've looked at these options before but never understood them well enough to actually yield the results I needed. I'll be using grep -rns from now on. –  Matt Potts Apr 4 '12 at 9:23
grep "add_action('save_post'," ./* -R
  1. You can grep all files in current directory recursively with -R option.

  2. Search string can be surrounded with ".

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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