74

I need to search a pattern in a directory and save the names of the files which contain it in an array.

Searching for pattern:

grep -HR "pattern" . | cut -d: -f1

This prints me all filenames that contain "pattern".

If I try:

targets=$(grep  -HR "pattern" . | cut -d: -f1)
length=${#targets[@]}
for ((i = 0; i != length; i++)); do
   echo "target $i: '${targets[i]}'"
done

This prints only one element that contains a string with all filnames.

output: target 0: 'file0 file1 .. fileN'

But I need:

 output: target 0: 'file0'
 output: target 1: 'file1'
 .....
 output: target N: 'fileN'

How can I achieve the result without doing a boring split operation on targets?

anubhava
  • 761,203
  • 64
  • 569
  • 643
Luca Davanzo
  • 21,000
  • 15
  • 120
  • 146
  • Other answer is a generic way to build an array by running any command and this question is specific to `grep --null -HR` to produce output with NUL bytes. – anubhava Nov 30 '21 at 08:08

1 Answers1

113

You can use:

targets=($(grep -HRl "pattern" .))

Note use of (...) for array creation in BASH.

Also you can use grep -l to get only file names in grep's output (as shown in my command).


Above answer (written 7 years ago) made an assumption that output filenames won't contain special characters like whitespaces or globs. Here is a safe way to read those special filenames into an array: (will work with older bash versions)

while IFS= read -rd ''; do
   targets+=("$REPLY")
done < <(grep --null -HRl "pattern" .)

# check content of array
declare -p targets

On BASH 4+ you can use readarray instead of a loop:

readarray -d '' -t targets < <(grep --null -HRl "pattern" .)
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • spectacular! I was already taking a look at "-l" option, btw great hit. Can you explain why works adding two brackets? – Luca Davanzo Jul 22 '14 at 15:02
  • 2
    That is syntax of array creation in BASH. If you remove outer `(..)` then you are merely assigning outout of `grep` to a simple shell variable which won't be treated as array. – anubhava Jul 22 '14 at 15:05
  • 2
    If that is the possibility then use `grep --null` with `IFS=` to create array – anubhava Jul 22 '14 at 16:55
  • Does this work with Posix-ly OS'es, like some of the BSDs and Solaris? I don't see [`-H` or `-R`](http://pubs.opengroup.org/onlinepubs/009604499/utilities/grep.html). – jww Jul 12 '16 at 21:02
  • `-R` may not be available in older `grep`. Alternative is to use `find -exec grep` on those systems – anubhava Jul 12 '16 at 21:05