Bash comparison between numbers fail - bash

I think I'm missing something with variable types...why the following script, that is supposed to read a number of lines and compare this number to 1 always enters the if even though it returns exactly 1?
status() {
lines=`ps aux | grep myprocess | wc -l` #returns 1
if [ $lines -gt 1 ]; then
echo "Process is up"
else
echo "Process is down"
fi
}

Solved by using melpomene's suggestion to use egrep instead of grep.
Strangely enough that command had several lines printed when ran as init script.

Related

Bash: how do I convert a command with a number result then compare it with an operator

I am trying to execute a word count command on a log file and if the file has the "error" string, I want to take some action, but I can't seem to properly convert the grep to word count command to a real number so it compares properly to the greater than zero. So far with several variations, the conditional statement is always true.
if ((grep -Ei "error" myfile.log | wc -l)) > 0; then echo 1; else echo 0; fi
First of all, you can write conditions based on the exit code of programs.
If grep finds a matching line, it exits with success:
if grep -qEi "error" myfile.log; then echo 1; else echo 0; fi
I added the -q flag to not print the matching line, as you probably don't need it.
I strongly recommend to use the above solution, without wc.
But for the sake of completeness, here's some more explanation about different ways of comparing numbers.
One way to compare numbers is with -gt ("greater than") within [ ... ]:
if [ $(grep -Ei "error" myfile.log | wc -l) -gt 0 ]; then echo 1; else echo 0; fi
You can read about other operators within [ ... ] in help test.
Or using arithmetic context within ((...)):
if (($(grep -Ei "error" myfile.log | wc -l) > 0)); then echo 1; else echo 0; fi
Notice that in both of these examples I wrapped the grep ... | wc -l within a $(...) sub-shell to capture the output.
The syntax you wrote is incorrect.

Search for value and print something if found (BASH)

I have the following list:
COX1
COX1
COX1
COX1
COX1
Cu-oxidase
Cu-oxidase_3
Cu-oxidase_3
Fer4_NifH
and I want to search if COX1 and Cu-oxidase is in the list, I want to print xyz, if Cu-oxidase_3 and Fer4_NifHis in the list too (independent if the first two are in the list, then it should print abc.
This is what I could script so far:
if grep 'COX1' file.txt; then echo xyz; else exit 0; fi
but it is of course incomplete.
Any solution to that?
ideally my output would be:
xyz
abc
Awk lets you easily search for multiple regular expressions and print something else than the matched string itself. (grep can easily search for multiple patterns, too, but it will print the match or its line number or file name, not some arbitrary string.)
The following assumes that you have a single token per line. This assumption makes the script really simple, though it would also not be hard to support other scenarios.
awk '{ a[$1]++ }
END { if (("COX1" in a) && ("Cu-oxidase" in a)) print "xyz";
if (("Cu-oxidase_3" in a) && ("Fer4_NifH" in a)) print "abc" }' file.txt
This builds an associative array of each token (actually the first whitespace-separated token on each line) and then at the end, when it has read every line in the file, checks whether the sought tokens exist as keys in the array.
Performing a single pass over the input file is a big win especially if you have a large input file and many patterns. Just for completeness, the syntax for performing multiple passes with grep is very straightforward;
if grep -qx 'COX1' file.txt && grep -qx 'Cu-oxidase' file.txt
then
echo xyz
fi
which can be further abbreviated to
grep -qx 'COX1' file.txt && grep -qx 'Cu-oxidase' file.txt && echo xyz
Notice the -x switch to require the whole line to match (otherwise the regex 'Cu-oxidase' would also match on the Cu-oxidase_3 lines).
Above is a very verbose way to achieve this. There are ways to write the same with less ifs and less greps, but I really wanted to show you the logic:
you run a grep command, check for its return value with $?, and finally acts on the conditions.
# default values
HAS_COX1=0
HAS_CUOX=0
HAS_CUO3=0
HAS_FER4=0
# run silently grep
grep -q 'COX1' file.txt
# check for return value and set variable accordingly
if [ $? -eq 0 ]; then HAS_COX1=1; fi
# same as above
grep -q 'Cu-oxidase' file.txt
if [ $? -eq 0 ]; then HAS_CUOX=1; fi
grep -q 'Cu-oxidase_3' file.txt
if [ $? -eq 0 ]; then HAS_CUO3=1; fi
grep -q 'Fer4_NifH' file.txt
if [ $? -eq 0 ]; then HAS_FER4=1; fi
if [ $HAS_COX1 -eq 1 ]; then
if [ $HAS_CUOX -eq 1 ]; then
echo 'xyz'
exit 0
fi
fi
if [ $HAS_CUO3 -eq 1 ]; then
if [ $HAS_FER4 -eq 1 ]; then
echo 'abc'
exit 0
fi
fi
echo 'None of the checks where matched'
exit 1
Beware: this code is untested, so there might be bugs ☺
The code isn't perfect, as it cannot print both 'xyz' and 'abc' when both conditions are met (but that would be an easy fix with the syntax I provide). Also $HAS_CUOX will be set to 1 whenever $HAS_CUO3 is found (no boundary checking in the grep regex).
You could take that code further by using a single grep for each set of conditions to check, using something like 'COX1\|Cu_oxidase' as the regex for grep. And also fix the minor issues I mentioned above.
ideally my output would be:
xyz
abc
You added your expected output after I wrote the above script, but given the elements I gave you, you should be able to figure how to improve that (basically removing the exit 0 where I placed them, and doing exit 1 when no output has been given.
Or just remove all exits as a dirty solution.

How can I get the return value and matched line by grep in bash at once?

I am learning bash. I would like to get the return value and matched line by grep at once.
if cat 'file' | grep 'match_word'; then
match_by_grep="$(cat 'file' | grep 'match_word')"
read a b <<< "${match_by_grep}"
fi
In the code above, I used grep twice. I cannot think of how to do it by grep once. I am not sure match_by_grep is always empty even when there is no matched words because cat may output error message.
match_by_grep="$(cat 'file' | grep 'match_word')"
if [[ -n ${match_by_grep} ]]; then
# match_by_grep may be an error message by cat.
# So following a and b may have wrong value.
read a b <<< "${match_by_grep}"
fi
Please tell me how to do it. Thank you very much.
You can avoid the double use of grep by storing the search output in a variable and seeing if it is not empty.
Your version of the script without double grep.
#!/bin/bash
grepOutput="$(grep 'match_word' file)"
if [ ! -z "$grepOutput" ]; then
read a b <<< "${grepOutput}"
fi
An optimization over the above script ( you can remove the temporary variable too)
#!/bin/bash
grepOutput="$(grep 'match_word' file)"
[[ ! -z "$grepOutput" ]] && (read a b <<< "${grepOutput}")
Using double-grep once for checking if-condition and once to parse the search result would be something like:-
#!/bin/bash
if grep -q 'match_word' file; then
grepOutput="$(grep 'match_word' file)"
read a b <<< "${grepOutput}"
fi
When assigning a variable with a string containing a command expansion, the return code is that of the (rightmost) command being expanded.
In other words, you can just use the assignment as the condition:
if grepOutput="$(cat 'file' | grep 'match_word')"
then
echo "There was a match"
read -r a b <<< "${grepOutput}"
(etc)
else
echo "No match"
fi
Is this what you want to achieve?
grep 'match_word' file ; echo $?
$? has a return value of the command run immediately before.
If you would like to keep track of the return value, it will be also useful to have PS1 set up with $?.
Ref: Bash Prompt with Last Exit Code

Bash IF statement

rather noobie question here.. i think. but i cant get this script to work. It is going to be included inside a script that i asked about here a few days ago (BASH output column formatting). basically i want to be able to scrape a site for a portion of text and return a ONLINE/OFFLINE answer. I apologize for poor formatting and weird variable names. Thanks for taking a look and helping me out!
#!/bin/bash
printf "" > /Users/USER12/Desktop/domainQueryString_output.txt
domainCurlRequest="curl https://www.google.com/?gws_rd=ssl"
ifStatementConditional="grep 'google.com' /Users/USER12/Desktop/domainQueryString_output.txt | wc -l"
echo $($domainCurlRequest) >> /Users/USER12/Desktop/domainQueryString_output.txt
if [ $ifStatementConditional -eq 2 ] ;
then second_check="online"
else second_check="DOMAIN IS OFFLINE"
fi
echo $second_check
i keep getting the following error when trying to run this script
/Users/USER12/Desktop/domain_status8working.sh: line 6: [: too many arguments
i tried to rewrite another way but got same errors so my logic or syntax or something is off.
Thanks again for taking a look and helping me out!!!
ifStatementConditional="grep 'google.com' /Users/USER12/Desktop/domainQueryString_output.txt | wc -l"
This is a string assignment. You probably want backticks, or the $() construct. Otherwise, $ifStatementConditional will never equal 2
if [ $ifStatementConditional -eq 2 ] ;
This is expanded as:
if [ grep 'google.com' /Users/USER12/Desktop/domainQueryString_output.txt | wc -l -eq 2 ] ;
Which explains your error.
I think you meant that:
#!/bin/bash
curl "https://www.google.com/?gws_rd=ssl" > /Users/USER12/Desktop/domainQueryString_output.txt
ifStatementConditional=$("grep 'google.com' /Users/USER12/Desktop/domainQueryString_output.txt | wc -l")
if [ $ifStatementConditional -eq 2 ] ; then
second_check="online"
else
second_check="DOMAIN IS OFFLINE"
fi
echo $second_check
No need to do printf "" > somefile.txt when you do a curl after, and you append to that file
$() is to capture subshell output. That what was missing here.

Check number of lines returned by bash command

I have a command similar to this:
LIST=$(git log $LAST_REVISION..$HEAD --format="%s" | egrep -o "[A-Z]-[0-9]{1,4}" | sort -u)
Now, I need to do something if $LIST returned zero or more lines. Here's what I've tried:
if [ ! $($LIST | wc -l) -eq 0 ]; then
echo ">0 lines returned"
else
echo "0 lines returned"
fi
But it throws me an error. What's the correct syntax of doing this (with some details on the syntax used, if possible)?
To check whether a variable is empty, use test -z, which can be written several ways:
test -z "$LIST"
[ -z "$LIST" ]
with bash (or many other "modern" shells):
[[ -z $LIST ]]
I prefer the last one, as long as you're using bash.
Note that what you are doing: $($LIST | ...) is to execute $LIST as a command. That is almost certain to create an error, and guaranteed to do so if $LIST is empty.

Resources