I'm using this find command to search all files in a directory ending with .err and .out. I'm using -exec with grep to search some content inside the files. But I can't figure out how to redirect each grep command to a file.
This my command:
find ./Documents/ -type f \( -name "*.out" -o -name "*.err" \) -exec sh -c "grep out {}; grep err {}" \;
I have tried this but it does not work (the files created are empty):
find ./Documents/ -type f \( -name "*.out" -o -name "*.err" \) -exec sh -c "grep out > file1 {}; grep err > file2 {}" \;
Thank you very much for any help you can provide.
CodePudding user response:
The conventional syntax is grep pattern inputfile >outputfile
so that's what I would suggest.
However, you also should avoid {}
inside -exec sh -c '...'
because it will break if the file name contains shell metacharacters. You are creating a new shell inside the single quotes and inside that script, file names with, for example, single quotes need to have them escaped or otherwise handled.
Fortunately, the workaround is simple; variables which contain these charachers are fine (but you need to double-quote the variable interpolation, too!)
I'm also guessing you don't want to overwrite the results from the previous -exec
each time find
finds a new file, so I changed >
to >>
.
find ./Documents/ -type f \( \
-name "*.out" -o -name "*.err" \) \
-exec sh -c 'grep out "$1">>file1
grep err "$1" >>file2
' _ {} \;
Another improvement would be to use -exec ... {}
to run a single -exec
for as many files as possible; you will then want to add a loop to the inner script.
find ./Documents/ -type f \( \
-name "*.out" -o -name "*.err" \) \
-exec sh -c 'for f; do
grep out "$f">>file1
grep err "$f">>file2
done' _ {}
Depending on your use case, you might be able to get rid of the loop and just run grep
directly on all the files.
find ./Documents/ -type f \( \
-name "*.out" -o -name "*.err" \) \
-exec sh -c '
grep -H out "$@">>file1
grep -H err "$@">>file2
' _ {}
The -H
option turns off reporting of the file name for each match, which is otherwise enhbled by default if you run grep
on more than one file.
See also When to wrap quotes around a shell variable? and https://mywiki.wooledge.org/BashFAQ/020
CodePudding user response:
You have wrong sequence in grep command. You should also redirect to append using '>>'. Otherwise your previous grep output will be overwritten by the next file found by the find command.
Try this command below:
find ./Documents/ -type f \( -name "*.out" -o -name "*.err" \) -exec sh -c "grep 'out' {} >> file1; grep 'err' {} >> file2" \;