Don't store it in variable, at least not a normal string variable. There is no way for the string variable to keep the difference between the space inside each argument and the space delimiting them.
grep -lr "$pattern" "$LOG_FILE_PATH" | while IFS= read -r file; do cp "$file" temp/; done
Also note that you don't need to cut the grep result, as the -l
flag gives you just the file names, exactly what you wanted. -H
is the default so it's not needed, and -n
is unnecessary if you're just going to cut it off.
This will not work if you have files containing newline in their names. As a solution, you can tell grep
(and read
) to use NUL for delimiter.
grep -lr --null "$pattern" "$LOG_FILE_PATH" | while IFS= read -d $'\0' -r file; do cp "$file" temp/; done
Alternately, you can use xargs
instead of while
+read
:
grep -lr --null "$pattern" "$LOG_FILE_PATH" | xargs --null -I {} cp {} temp/
If you have to store it in a variable, use the same pattern as above to store it into an array variable. This way space is not needed as the argument delimiter.
declare -a files
while IFS= read -d $'\0' -r file; do files+=("$file"); done < <(grep -lr --null "$pattern" "$LOG_FILE_PATH")
cp "${files[@]}" temp/
Here's another way to do it (though this will not work if filenames include newline characters, as mapfile
does not support changing the delimiter):
mapfile -t files < <(grep -lr "$pattern" "$LOG_FILE_PATH")
cp "${files[@]}" temp/
If the number of files to copy is very big, the while
and xargs
solutions will still work, but those that simply plop the entire array into one cp
command may not.