Grep and Sed with Spaces in Filenames

grep and sed with spaces in filenames

Add the -Z (aka --null) flag to grep, and the -0 (also aka --null) flag to xargs.
This will output NUL terminated file names, and tell xargs to read NUL terminated arguments.

eg.

grep -irlZ $schema $WORKDIR/ | xargs -0 sed -i 's/'"$schema"'/EXI1/gI'

grep files with whitespaces in filename

Quote $i

cat filelist | while read i; do grep "pattern" "$i"; done

grep the filename using sed

echo "result_0.01.dat resultFile" | sed  "s|.*.dat|someOtherText.dat|g"

what happens here in sed part is:

we substitude (s flag at the beginning of sed)
we find everything till .dat. We replace that part with someOtherText.
and we do it globally (g flag at the end)

grep cannot read filename after find folders with spaces

The issue is that your array contains filenames surrounded by literal " quotes.

But worse, find's -exec cmd {} \; executes cmd separately for each file which can be inefficient. As mentioned by @TomFenech in the comments, you can use -exec cmd {} + to search as many files within a single cmd invocation as possible.

A better approach for recursive search is usually to let find output filenames to search, and pipe its results to xargs in order to grep inside as many filenames together as possible. Use -print0 and -0 respectively to correctly support filenames with spaces and other separators, by splitting results by a null character instead - this way you don't need quotes, reducing possibility of bugs.

Something like this:

find . -type f -not -path './.git/*' -print0 | xargs -0 egrep '(GNU)'

However in your question you had grep -q in a loop, so I suspect you may be looking for an error status (found/not found) for each file? If so, you could use -l instead of -q to make grep list matching filenames, and then pipe/send that output to where you need the results.

find . -print0 | xargs -0 egrep -l pattern > matching_filenames

Also note that grep -E (or egrep) uses extended regular expressions, which means parentheses create a regex group. If you want to search for files containing (GNU) (with the parentheses) use grep -F or fgrep instead, which treats the pattern as a string literal.

Make xargs handle filenames that contain spaces

The xargs command takes white space characters (tabs, spaces, new lines) as delimiters.

You can narrow it down only for the new line characters ('\n') with -d option like this:

ls *.mp3 | xargs -d '\n' mplayer

It works only with GNU xargs.

For MacOS:

ls *.mp3 | tr \\n \\0 | xargs -0 mplayer

The more simplistic and practically useful approach (when don't need to process the filenames further):

mplayer *.mp3

Find and xargs to correctly handle filenames with spaces in their names

find . -name "*.php" -print0 | xargs -0 sed -i 's/string1/string2/g'

You can also do it without xargs at all:

find . -name "*.php" -execdir sed -i 's/string1/string2/g' {} +

Bash and filenames with spaces

Try this:

(IFS=$'\n'; grep -li 'regex' $(<listOfFiles.txt))

IFS is the Internal Field Separator. Setting it to $'\n' tells Bash to use the newline character to delimit filenames. Its default value is $' \t\n' and can be printed using cat -etv <<<"$IFS".

Enclosing the script in parenthesis starts a subshell so that only commands within the parenthesis are affected by the custom IFS value.



Related Topics



Leave a reply



Submit