Check number of lines returned by bash command - bash

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.

Related

Bash comparison between numbers fail

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.

Problem with understanding output in bash code

I have following code in bash:
#!/bin/sh
w=`who | grep $1`
if [ -z "$w" ]; then
echo "$1 ... ";
fi
Could you help me to understand the output of this code.
I can see that it will display given parameters from command line ($1, $2...)
But I don't really understand these 2 lines:
w=`who | grep $1`
if [ -z "$w" ]; then
Could you provide me with some help as I cannot really find much information
Looks to me a script to check if the username you pass as parameter to the script is logged on the system.
For example if you call it with ./check.sh nonexistinguser it will print nonexistinguser ....
Explanation:
w=`who | grep $1`
Execute who, which displays who is logged in, then grep the result for whatever parameter you passed to the script ($1), store the result in a variable called w; have a look here for the docs on -z
if [ -z "$w" ]; then
If "$w" has length zero, execute the body of the if.

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

Combine these two IF statements into one?

Any way to combine these two IF statements into one...
if [ -n "$(system_profiler SPPrintersDataType | grep Shared | grep Yes)" ]; then
echo 1
fi
if [ -n "$(system_profiler SPPrintersDataType | grep 'System Printer Sharing: Yes')" ]; then
echo 1
fi
Add || short circuit evaluation in between:
if [ -n ... ] || [ -n ... ]; then ## Something; fi
|| is treated as logical OR (and && is logical AND).
In your case:
if [ -n "$(system_profiler SPPrintersDataType | grep Shared | grep Yes)" ] || [ -n "$(system_profiler SPPrintersDataType | grep 'System Printer Sharing: Yes')" ]; then
echo 1
fi
Just to note, if you use the bash keyword [[, then the following is valid too:
if [[ -n ... || -n ... ]]; then ## Something; fi
[[ -n $(system_profiler SPPrintersDataType | grep Shared | grep Yes)$(system_profiler SPPrintersDataType | grep 'System Printer Sharing: Yes') ]] && echo 1
Note:
You want to echo 1 if either one of the strings is non-empty or if the other one is non-empty. In this case, it is simpler to catenate the strings and look at the result: If the result is non-empty, at least one of the imput strings must be non-empty.
There is no need to use an if statement in this case (although it is not forbidden).
You don't need to quote the argument to -s, if you use [[ ... ]] for testing the string.
When you grep for Shared, should it be allowed that the word Yes appears before the word Shared in the line? If not, it would be simpler to write grep 'Shared.*Yes.
Since you are not interested in the actual output of the grep command, but only in the fact, that it matches, something like this would also work:
{system_profiler SPPrintersDataType|grep -q 'Shared.*Yes} || {system_profiler SPPrintersDataType|grep -Fq 'System Printer Sharing: Yes'} && echo 1
Finally, assuming that the system_profiler command produces the same output in both invocations, the code could be simplified to:
{system_profiler SPPrintersDataType|grep -Eq 'Shared.*Yes|System Printer Sharing: Yes'} && echo 1
This basically says: If there is a line in system_profiler which contains Shared...Yes OR a line containing System Printer Sharing Yes, then echo 1. You need the -E in inorder to get the | to work in the regexp pattern.
Admittedly, all these suggestions mean that you get only one 1 being echoed, if the condition is fulfilled, while in your original solution, you get two 1 being echoed, if both conditions are fulfilled. Therefore, my solution is not exactly equivalent to yours. However, since you explicitly said that you wanted to combine the cases, I think this is acceptable.
I don't know how the output of your system_profiler looks, so going a bit on guesswork here. If the Shared and Yes are always in the same order within a line, you can grep for them together with
grep 'Shared.*Yes'
and you can grep for both of your expressions in one pass with
grep 'Shared.*Yes\|System Printer Sharing: Yes'
You can then write your command as
system_profiler SPPrintersDataType \
| grep -q 'Shared.*Yes\|System Printer Sharing: Yes' \
&& echo 1
Note that we use grep -q to suppress output, as we're only interested in the return code.
Note also that if both of the strings are present, we only output one 1 - I'm guessing that's what you want, but I mention it as it is a difference from your script.

How can I make bash evaluate IF[[ ]] from string?

I am trying to create a "Lambda" style WHERE script.
I want lambdaWHERE to take piped input and pass it through if condition after given as arguments is met. Like xargs I use {} to represent what comes down the pipe.
I call command like:
ls -d EqAAL* | lambdaWHERE.sh -f {}/INFO_ACTIVETICK
I want the folder names passed through if they contain a file called INFO_ACTIVETICK
Here is the script:
#!/bin/sh
#set -x
ARGS=$*
while read i
do
CMD=`echo $ARGS | sed 's/{}/'$i'/g'`
if [[ $CMD ]]
then
echo $i
fi
done
But when I run it a mysterious "-n" appears...
$ ls -d EqAAL* | /q/lambdaWHERE.sh -f {}/INFO_ACTIVETICK
+ ARGS='-f {}/INFO_ACTIVETICK'
+ read i
++ echo -f '{}/INFO_ACTIVETICK'
++ sed 's/{}/EqAAL-1m/g'
+ CMD='-f EqAAL-1m/INFO_ACTIVETICK'
+ [[ -n -f EqAAL-1m/INFO_ACTIVETICK ]]
+ echo EqAAL-1m
EqAAL-1m
+ read i
How can I get the bit in the [[ ]] correct?
You were quite close. you only need to switch to the standard POSIX [ $CMD ] and it will work.
The main difference between using [[ $CMD ]] and [ $CMD ] is that the first has fewer surprises and you need not quote variables. That also means that a variable is though of as one token and cannot have a whole expression in it like you are trying. [ $CMD ] however works the same way as the original shell where [ was just a command an thus need explicit quotations in order to interpret something with spaces as one argument.
There is a relevant question about the differences between [[ ...]] and [ ..]

Resources