1

After answering this question, I am now wondering the best way to further process the null-separated output of find -print0.

The following command would search for a phrase in the first 10 files that find returns - maybe we don't want to search too many at one time.

find . -maxdepth 1 | head -10 | xargs grep "Specific Phrase"

However, if there are newlines or spaces in the filenames, this can become a challenge as they will mess up our xargs command.

How could I write the following so it works - can I do this in bash or do I need to use a tool like awk to break this string up at the nulls?

find . -maxdepth 1 -print0 | head -10 | xargs -0 grep "Specific Phrase"

It seems the other words I could use to describe this is how to change the field separator to be a null character.

Community
  • 1
  • 1
Adam B
  • 3,775
  • 3
  • 32
  • 42
  • **Which** shell? The facilities for this are far better in bash or ksh than POSIX sh. – Charles Duffy Feb 25 '16 at 00:21
  • I realized I didn't know how to do it in any shell. Lets say `bash` as it is very common. – Adam B Feb 25 '16 at 00:24
  • That was kind of a "leading comment", as the *solution* @CharlesDuffy provided below is implemented in bash, but the question mentioned only tools that are external to most shells. I would love to see a Charles-approved shell-agnostic answer to this question, or at least one that works in a POSIX shell. – ghoti Feb 25 '16 at 12:49
  • I posted an `awk` answer below as well that does not require complex shell machinations. – Adam B Feb 26 '16 at 15:57

2 Answers2

2

In bash, you could do something like the following:

head0() {
  local item i=0
  while IFS= read -r -d '' item && (( ++i <= "$1" )); do
    printf '%s\0' "$item"
  done
}

find . -maxdepth 1 -print0 | head0 10 | xargs -0 grep "Specific Phrase"

The relevant idioms here are IFS= read -r -d '' item to read, and printf '%s\0' "$item" to write.

To explain that read command in detail:

  • IFS= prevents whitespace from being trimmed from either the beginning or end of any string
  • read -r prevents literal backslashes from being consumed or suppressed.
  • -d '' sets the first character of the string '' -- an empty NUL-delimited string, of which the first character is thus NUL -- as the character which will terminate the read.
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
2

Here is another possible option using awk, which was presented as part of an answer to this question but is also applicable here.

find . -maxdepth 1 -print0 \
    | awk 'NR<=10;NR>10{exit}' RS="\0" ORS="\0" \
    | xargs -0 grep "Specific Phrase"
Community
  • 1
  • 1
Adam B
  • 3,775
  • 3
  • 32
  • 42