I am trying to build a script that will search for a pattern in log files present in a folder. This folder contains a mix of uncompressed log files, and of logs compressed in gunzip files. I only want to search in the gunzip files if the pattern wasn't found in the uncompressed log files. Constraint: the user that triggers the script will never have permission to read some of the files in this folder.
The problem is that even though grep actually outputs results or not, it also encounters some permission denied. And because of this the exit code is always "2". E.g when it outputs results:
[user@mypc ~]$ grep -rnw '/usr/toto/log' -e "pattern"
grep: /usr/toto/log/privileged.log.2025-01-10: Permission denied
grep: /usr/toto/log/privileged.out.1: Permission denied
/usr/toto/log/testontargz.log:1:pattern
grep: /usr/toto/log/privileged.out.3: Permission denied
grep: /usr/toto/log/privileged.log.2025-01-17: Permission denied
grep: /usr/toto/log/privileged.out.2: Permission denied
/usr/toto/log/teston2.log:1:pattern
[user@mypc ~]$ echo $?
2
I know that grep -rnws will get rid of the "Permission denied" in the output of the terminal, but it obviously won't change the exit code from "2" to "1" when it doesn't output results (or "0" when it actually output results).
I've been trying to use "$?" in my if statement to match the exit code 1, but it will obviously never succeed in the current state. So I suppose that using "$?" is not the right choice here but I'm not that good a scripting... How can I modify this script?
#!/bin/sh
printf '\n'
# Search for the error in not compressed log files
printf '%s\n' ">> Errors found in the log file(s):"
grep -rnws '/usr/toto/log' -e "$1"
# Only search in the compressed files if the above grep didn't output any actual result
if [ $? -eq 1 ]; then
# Search for the error in compressed log files
printf '\n'
pattern=$1; shift
for x do
if case "$x" in
*.gz|*.[zZ]) <"$x" gzip -dc | grep -q -e "$pattern";;
esac
then
printf '%s\n' ">> Error found in one of the log files that is stored in the file $x"
fi
done
fi
printf '\n'
I'm calling the script like this: myscript.sh patterntofind /usr/toto/log/compressedfile.*.gz
Thank in advance
It's kind of a kluge, but you can use:
grep -rnw '/usr/toto/log' -e "pattern" | grep '.*'
Explanation: The second grep
just searches the output of the first for... anything. Any output at all, i.e. any lines the first grep
matched. If it finds that, it succeeds; but if there's no output from the first grep
, it'll fail.
Caveats: If you have bash's pipefail
option set, then the error from the first grep
will show up in $?
if the second grep
succeeds; in this case, check ${PIPESTATUS[1]}
instead of $?
. Also, since the regular output from the first grep
goes through the second, but its error messages go straight to the terminal (via stderr), the various output may arrive out of order.