I have a log file. I want to scan the occurrences of the string
"RC = x"
If there is >=1 one occurrence where RC = 0 is not TRUE then I want to flag it as failure
Can I do this as shell function?
You can use grep for this:
grep -q "RC = [^0]" logfile && {
echo "Logfile is a failure"
other commands
exit
}
The -q puts grep into silence mode: no output, the [^0] matches any non-zero value for RC. Grep will return a failure status if no matches are found and a success status if any are. The && is a conditional "and" so if there are any non-zero values for RC, then the grep will succeed and the test is a failure.
Alternately, you can put the grep into an if statement. In this case:
if grep -s "RC = [^0]" logfile
then
echo "Logfile is a failure"
else
echo "Logfile is a success"
fi
See man grep for more grep options.
Related
file.txt
example=0x12; non-match
grep -w "example=0x0" file.txt
I am trying to match exact string using grep and it looks like
echo $? always returns 1.
In this case, the output should have been 0. I have tried -F too.
You need the -q option if you're just checking the exit status. See below for examples
$ grep -qw "A" <<< "AAA"; echo $?
1
$ grep -qw "A" <<< "A"; echo $?
0
first word match fails, exit 1. Second one succeeds, exit 0.
How do I check if a variable contains characters (regex) other than 0-9a-z and - in pure bash?
I need a conditional check. If the string contains characters other than the accepted characters above simply exit 1.
One way of doing it is using the grep command, like this:
grep -qv "[^0-9a-z-]" <<< $STRING
Then you ask for the grep returned value with the following:
if [ ! $? -eq 0 ]; then
echo "Wrong string"
exit 1
fi
As #mpapis pointed out, you can simplify the above expression it to:
grep -qv "[^0-9a-z-]" <<< $STRING || exit 1
Also you can use the bash =~ operator, like this:
if [[ ! "$STRING" =~ [^0-9a-z-] ]] ; then
echo "Valid";
else
echo "Not valid";
fi
case has support for matching:
case "$string" in
(+(-[[:alnum:]-])) true ;;
(*) exit 1 ;;
esac
the format is not pure regexp, but it works faster then separate process with grep - which is important if you would have multiple checks.
Using Bash's substitution engine to test if $foo contains $bar
bar='[^0-9a-z-]'
if [ -n "$foo" -a -z "${foo/*$bar*}" ] ; then
echo exit 1
fi
I need to use cron and bash to check if IP 111.222.333.444 is still valid for host sub.domain.com.
I have tried grep with -Pzo, but it didn't work. I don't want to install pcregrep.
#!/bin/bash
ipaddressused=$1
#Run a dig for sub.domain.com:
ipaddresscurrent='dig +short sub.domain.com'
echo "$ipaddresscurrent" | grep -Pzo "$ipaddressused" && echo "found" && exit 0 || echo "not found" && exit 1
ipaddresscurrent returns multiple IPs, one per line.
How do I make this work?
Wouldn't this be enough?
#!/bin/bash
ipaddressused=$1
if grep -q -P "$ipaddressused" < <(dig +short sub.domain.com); then
echo "found"
exit 0
else
echo "not found"
exit 1
fi
What was wrong with your script?
The line
ipaddresscurrent='dig +short sub.domain.com'
assigns the string dig +short sub.domain.com to the variable ipaddresscurrent. You probably, instead, wanted to assign to the variable ipaddresscurrent the output of the command dig +short sub.domain.com. This is done either using the old and deprecated backticks:
ipaddresscurrent=`dig +short sub.domain.com`
(but please don't ever use backticks!) or the more modern, robust and nestable $(...) as:
ipaddresscurrent=$(dig +short sub.domain.com)
grep -Pzo doesn't really do what you're expecting. Instead you want to run grep quiently (hence the -q flag) and check its output, so the following would have been valid:
echo "$ipaddresscurrent" | grep -q -P "$ipaddressused" && echo "found" && exit 0 || echo "not found" && exit 1
Since you don't really need the variable ipaddresscurrent, I prefered to use bash's process substitution to feed grep.
Also, don't use long chains of && || &&'s, it's hard to read, and can have some subtle side effects.
If you want to stick with your variable, you need a here-string as so:
#!/bin/bash
ipaddressused=$1
ipaddresscurrent=$(dig +short sub.domain.com)
if grep -q -P "$ipaddressused" <<< "$ipaddresscurrent"; then
echo "found"
exit 0
else
echo "not found"
exit 1
fi
As you note in your comment:
should be noted that if the $ipaddressused supplied is 111.222.333.4 and 111.222.333.456 is present on the list a match will also occur. this could cause problems.
I actually didn't really know if this was a requested feature or not (since the argument of the script is a regex, that's actually why I left the -P flag). If you really want to exactly match an IP, here's how you could proceed:
#!/bin/bash
if grep -q "^${1//./\.}$" < <(dig +short sub.domain.com); then
echo "found"
exit 0
else
echo "not found"
exit 1
fi
assuming that dig used this way will output only one ip per line.
How can I reduce the following bash script?
grep -P "STATUS: (?!Perfect)" recess.txt && exit 1
exit 0
It seems like I should be able to do it with a single command, but I have a total of 3 here.
My program should:
Read recess.txt
Exit 1 (or non-zero) if it contains a line with "STATUS: " of NOT "Perfect"
Exit 0 if no such line exists (i.e. all "STATUS: " lines are "Perfect")
The answer award goes to the tightest script. Thanks!
Example files
Program should have exit status 0 for this file:
FILE: styles.css
STATUS: Perfect!
FILE: contour-styles.css
STATUS: Perfect!
Program should have exit status 1 (or non-zero) for this file:
FILE: styles.css
STATUS: Perfect!
FILE: contour-styles.css
STATUS: Busted
FAILURES: 1 failure
Id's should not be styled
1. #asdf
Just negate the return value.
! grep -P "STATUS: (?!Perfect)" recess.txt
I came across this, needing an onlyif statement for Puppet. As such, Tgr's bash solution wouldn't work, and I didn't want to expand the complexity as in Christopher Neylan's answer.
I ended up using a version inspired by Henri Schomäcker's answer, but notably simplified:
grep -P "STATUS: (?!Perfect)" recess.txt; test $? -eq 1
Which very simply inverts the exit code, returning success only if the text is not found:
If grep returns 0 (match found), test 0 -eq 1 will return 1.
If grep returns 1 (no match found), test 1 -eq 1 will return 0.
If grep returns 2 (error), test 2 -eq 1 will return 1.
Which is exactly what I wanted: return 0 if no match is found, and 1 otherwise.
if anyone gets here looking for a bash return code manipulation:
(grep <search> <files> || exit 0 && exit 123;)
this will return 0 (success) when grep finds nothing, and return 123 (failure) when it does. The parenthesis are in case anyone test it as is on the shell prompt. with parenthesis it will not logout on the exit, but just exit the subshell with the same error code.
i use it for a quick syntax check on js files:
find src/js/ -name \*js -exec node \{\} \; 2>&1 | grep -B 5 SyntaxError || exit 0 && exit 1;
To make it work with set -e surround it in a sub-shell with ( and ):
$ cat test.sh
#!/bin/bash
set -ex
(! ls /tmp/dne)
echo Success
$ ./test.sh
+ ls /tmp/dne
ls: cannot access /tmp/dne: No such file or directory
+ echo Success
Success
$ mkdir /tmp/dne
$ ./test.sh
+ ls /tmp/dne
$
Just negating the return value doesn't work in a set -e context. But you can do:
! grep -P "STATUS: (?!Perfect)" recess.txt || false
You actually don't need to use exit at all. Logically, no matter what the result of grep, your script is going to exit anyway. Since the exit value of a shell script is the exit code of the last command that was run, just have grep run as the last command, using the -v option to invert the match to correct the exit value. Thus, your script can reduce to just:
grep -vqP "STATUS: (?!Perfect)" recess.txt
EDIT:
Sorry, the above does not work when there are other types of lines in the file. In the interest of avoiding running multiple commands though, awk can accomplish the entire shebang with something like:
awk '/STATUS: / && ! /Perfect/{exit 1}' recess.txt
If you decide you want the output that grep would have provided, you can do:
awk '/^STATUS: / && ! /Perfect/{print;ec=1} END{exit ec}' recess.txt
Use the special ? variable:
grep -P "STATUS: (?!Perfect)" recess.txt
exit $((1-$?))
(But note that grep may also return 2, so it's not clear what you'd want to occur in such cases.)
The problem with the grep answers is that if the file is empty you also get a clean response, as if the file had a perfect.
So personally I gave up on grep for this and used awk.
awk 'BEGIN{ef=2}; /STATUS: Perfect/{ ef=0;}; /STATUS: Busted/{ print;eff=3;}; END{exit (ef+eff)}' a.txt ; echo $?
This has exit status:
0 : Perfect and !Busted
2 : !Perfect and Busted
3 : Perfect and Busted
5 : !Perfect and !Busted
[ $(grep -c -P "STATUS: (?!Perfect)" recess.txt) -eq 0 ]
I also needed such a solution for writing puppet only if statements and came up with the following command:
/bin/grep --quiet 'root: root#ourmasterdomain.de' /etc/aliases; if [ $? -eq 0 ]; then test 1 -eq 2; else test 1 -eq 1; fi;
Since someone already posted a Puppet solution, I might as well add how to invert a shell command run by Ansible:
- name: Check logs for errors
command: grep ERROR /var/log/cassandra/system.log
register: log_errors
failed_when: "log_errors.rc == 0"
I.e. you just set the failed condition to the return code being 0. So this command fails if we do find the word ERROR in our logs.
I chose this rather than grep -v as that also inverts grep's output, so we would receive all DEBUG/INFO/WARN lines in log_errors.stdout_lines which we do not want.
I have a shell script in tcsh to which I pass an argument, the length of which can vary. The possible values of the argument are the letters -c,s,i,q,a. and also a combination of these letters. (e.g: cs,si,ca,iq,qa,csq,acs,csia ..etc). The order of the letters does not matter.
My problem is to check the argument for any character other than these 5 and if any of the valid character appear more than one time (zero time is ok). The script should check both the conditions and throw an error. Is there any regular expression that I can use with if statement for this purpose?
Here is a sample piece of code you can use. The use of an "X" is to force the comparison to be a string.
#!/bin/csh -f
if ( $#argv > 0 ) then
echo arg is $1
if ( X$1 =~ X-* ) then
echo "we have an argument"
if ( "X$1" =~ X-c[aeiou] ) then
echo I found -c followed by vowel
else if ( "X$1" =~ "X-c" ) then
echo I found -c alone
else
echo I found a -c but not a valid combo
endif
else
echo I found an unknown argument: $1
endif
endif
This will be easiest to do with two regex checks, one for validity of all letters and another to look for duplicate letters.
Take a look at this code:
#!/bin/tcsh
echo $1 | grep -q -e "[^csqai]"
if ( $? != 0 ) then
echo "Valid characters"
else
echo "Invalid characters"
endif
echo $1 | grep -q -e "\([csqai]\).*\1"
if ( $? != 0 ) then
echo "No repeated valid characters"
else
echo "Repeated valid characters"
endif
The first regex looks for all characters which are not valid and the second looks for any repeated characters
I don't know how to do these checks in tcsh, so I did them with grep. The -q flag makes grep silent. $? is 0 if no match is found.