I have the bash script below:
#!/bin/bash
#
[ $# -eq 1 -a $1 = "--help" -o $# -eq 0 ] && {
echo Help will come here
}
When I run it:
$ ./script
./script: line 3: [: too many arguments
$ ./script --help
Help will come here
As you can see, when I don't pass parameters ( $# -eq 0 ) it fails with "too many arguments".
So, I tested it directly in terminal:
$ a=1;b=2;c=3
$ [ $a -eq 1 -a $b -eq 2 -o $c -eq 3 ] && echo ok
ok
$ [ $a -eq 0 -a $b -eq 2 -o $c -eq 3 ] && echo ok
ok
$ [ $a -eq 0 -a $b -eq 0 -o $c -eq 3 ] && echo ok
ok
$ [ $a -eq 0 -a $b -eq 0 -o $c -eq 0 ] && echo ok
$ [ $a -eq 0 -a $b -eq 2 -o $c -eq 0 ] && echo ok
$ [ $a -eq 1 -a $b -eq 2 -o $c -eq 0 ] && echo ok
ok
So, if it works perfectly in terminal why doesn't it work passing parameters?
Thanks,
Express your condition like this :
[ $# -eq 1 ] && [ "$1" = "--help" ] || [ $# -eq 0 ]
Actually, [ is a command, and the following elements in the commands are subject to word splitting. If an argument is empty (or contains whitespace and is unquoted), you can run into surprises. Using -a and -o is deprecated.
Please note that, if you want to use the && logical operator (instead of an if statement) before your echo statement, you will need to enclose the above inside braces, else the operator precedence (coupled with lazy evaluation) may yield incorrect results.
{ [ $# -eq 1 ] && [ "$1" = "--help" ] || [ $# -eq 0 ] ; } && { echo...
If you do not mind using Bash-specific syntax, you could also write :
[[ $# -eq 1 && $1 = "--help" || $# -eq 0 ]]
Note that in this case, double-quoting $1 is not required, because the [[ ]] construct is special shell syntax, not a command, and what is inside is not subject to word splitting. Because there is a single test, you do not need to enclose it inside braces before your && { echo....
Your entire expression can be simplified to:
function help () {
printf "%s\n" "help is on it's way."
}
[[ $# -eq 0 || "$*" = "--help" ]] && help ; echo "done." && exit 0 ;
This checks if the total sum of arguments is zero, or the argument(s) equals "--help". If either of those two things are true then it proceeds to the help function, otherwise echo "done" and exit.
When you are executing the script without parameter, you are getting the error because your condition is matching with blank character, see below -
$sh -x kk.sh
+ '[' 0 -eq 1 -a = --help -o 0 -eq 0 ']'
kk.sh: line 3: [: too many arguments
As you can see that there is no value to match.
When you will execute below command in your terminal -
$[ $a -eq 1 -a $b -eq 2 -o $c -eq 3 ] && echo ok
-bash: [: too many arguments
$a=1;b=2;c=3
$[ $a -eq 1 -a $b -eq 2 -o $c -eq 3 ] && echo ok
ok ####it is printing this value bcoz you have set the variable to match, it doesn't matter condition is wrong or right but there is something to match.
To resolve this issue you can use one if condition in the beginning to assign a dummy value if there is no value.
Try this :-
[ $# -eq 1 ] || [ $1 = "--help" ] || [ $# -eq 0 ]
This way it will automatically display if --help is provided or 1 is typed.
I think $# is creating the problem as both there is $# for first and second conditions
Related
This has been already discussed, but I have a more different problem:
I have a function that needs to be called with $# as parameter.
If I put var=$(function $#) I just receive errors for every line where the function actions.
Meanwhile I used a workaroud:
I called the function first: function $#
Then I stored into the variable the result from the function: var=$?
But this works just if the function return is "succes" or "fail".
Any thoughts?
Code:
function()
{
if [ $1 -gt $x ]
then
return 0
fi
if [ $1 -eq $x ]
then
return 1
fi
if [ $1 -lt $x ]
then
return 2
fi
}
I want to store in my variable 0 , 1 or 2.
For this:
menu ()
{
if [ $# -gt 5 ] || [ $# -lt 1 ]
then
echo "Error! Script is: " $0
return
fi
echo "Insert reference number: "
read x
while [ $# -gt 0 ]
do
rez=$(function $#)
if [ $rez -eq 0 ]
then
echo "Nr >!" $1
fi
if [ $rez -eq 1 ]
then
echo "Nr =!" $1
fi
if [ $rez -eq 2 ]
then
echo "Nr <!" $1
fi
shift
done
}
Maybe use elifs so that you don't receive multiple values that are returned (also a case statement might be a better solution).
var=$(function $# >/dev/null 2>&1; echo $?) should do what you want, I believe?
I want to test the number of arguments passed to a Linux shell script. If the number of arguments is not 2 or 4, it should print something. Unfortunately it does not work. Can anyone explain what I am doing wrong?
#!/bin/bash
if [[ $# -ne 2 ]] || [[ $# -ne 4 ]];
then
echo "here";
fi
You should replace logical OR by logical AND, so :
#!/bin/bash
if [[ $# -ne 2 && $# -ne 4 ]]; then
echo "here"
fi
In arithmetic form:
#!/bin/bash
if (($# != 2 && $# != 4)); then
echo "here"
fi
As you can see, no need to use 2 [[ ]]
Logic.
if [[ $# -ne 2 ]] && [[ $# -ne 4 ]]; then
echo "here"
fi
In the following code I want to compare the command line arguments with the parameters but I am not sure what is the current syntax to compare the arguments with parameters..i.e "==" or "-eq".
#!/bin/bash
argLength=$#
#echo "arg = $1"
if [ argLength==0 ]; then
#Running for the very first
#Get the connected device ids and save it in an array
N=0
CONNECTED_DEVICES=$(adb devices | grep -o '\b[A-Za-z0-9]\{8,\}\b'|sed -n '2,$p')
NO_OF_DEVICES=$(echo "$CONNECTED_DEVICES" | wc -l)
for CONNECTED_DEVICE in $CONNECTED_DEVICES ; do
DEVICE_IDS[$N]="$CONNECTED_DEVICE"
echo "DEVICE_IDS[$N]= $CONNECTED_DEVICE"
let "N= $N + 1"
done
for SEND_DEVICE_ID in ${DEVICE_IDS[#]} ; do
callCloneBuildInstall $SEND_DEVICE_ID
done
elif [ "$1" -eq -b ]; then
if [ $5 -eq pass ]; then
DEVICE_ID=$3
./MonkeyTests.sh -d $DEVICE_ID
else
sleep 1h
callCloneBuildInstall $SEND_DEVICE_ID
fi
elif [ "$1" -eq -m ]; then
echo "Check for CloneBuildInstall"
if [ "$5" -eq pass ]; then
DEVICE_ID=$3
callCloneBuildInstall $SEND_DEVICE_ID
else
echo "call CloneBuildInstall"
# Zip log file and save it with deviceId
callCloneBuildInstall $SEND_DEVICE_ID
fi
fi
function callCloneBuildInstall {
./CloneBuildInstall.sh -d $SEND_DEVICE_ID
}
From help test:
[...]
STRING1 = STRING2
True if the strings are equal.
[...]
arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
-lt, -le, -gt, or -ge.
But in any case, each part of the condition is a separate argument to [.
if [ "$arg" -eq 0 ]; then
if [ "$arg" = 0 ]; then
Why not use something like
if [ "$#" -ne 0 ]; then # number of args should not be zero
echo "USAGE: "
fi
When/how to use “==” or “-eq” operator in test?
To put it simply use == when doing lexical comparisons a.k.a string comparisons but use -eq when having numerical comparisons.
Other forms of -eq (equal) are -ne (not equal), -gt (greater than), -ge (greater than or equal), -lt (lesser than), and -le (lesser than or equal).
Some may also suggest preferring (( )).
Examples:
[[ $string == "something else" ]]
[[ $string != "something else" ]] # (negated)
[[ $num -eq 1 ]]
[[ $num -ge 2 ]]
(( $num == 1 ))
(( $num >= 1 ))
And always use [[ ]] over [ ] when you're in Bash since the former skips unnecessary expansions not related to conditional expressions like word splitting and pathname expansion.
I have a file like this
File name : hello.txt
{1:ABC}{2:BCD}{3:{108:20140619-2}}{4:
:97A::Hi//12345
:97A::Hi//12345
:93B::Hello//FAMT/00000,
:16S:FIN
-}{5:{CHK:BDG6789}}{S:{ABC:}{DEF:S}{WOM:ONHGRT}}
Now basically i'm checking for the existence of $ symbol and as well as :97A: AND im using the below if statement.
if [ `grep -c '\$' hello.txt` -gt 0 ] && [ `grep -c ":97A:" hello.txt` -gt 1 ]
then
echo "condition satisfied"
else
echo "condition not satisfied"
fi
if i execute this im getting condition satisifed echo statement. But id should be the other way round :( since im putting AND condition. Please help on this.
I also don't understand what you're asking, but from your code I conclude that you have troubles grepping for the dollar sign. I guess you need to escape the backslash as well if you use backticks:
$ echo 'foo$bar' > dollar.txt
$ echo 'foo_bar' > no_dollar.txt
$ [ `grep -c '\$' dollar.txt` -gt 0 ] && echo 1
1
$ [ `grep -c '\$' no_dollar.txt` -gt 0 ] && echo 1
1
$ [ `grep -c '\\$' dollar.txt` -gt 0 ] && echo 1
1
$ [ `grep -c '\\$' no_dollar.txt` -gt 0 ] && echo 1
$ [ `grep -c '\\$' no_dollar.txt` -gt 0 ] || echo 0
0
alternatively, use $() instead of backticks
Replace grep -c '\$' hello.txt by grep -c '\\$' hello.txt Then it will work as desired.
ex:
bash -x test.sh
++ grep -c '\$' hello.txt
+ '[' 0 -gt 0 ']'
+ echo 'condition not satisfied'
condition not satisfied
PS: bash -x is your friend :)
I recommend executing your grep commands in a subshell with the $ syntax, then doing the comparison. In my opinion this is the cleaner way and requires you to be less of an escape artist.
if [ $(grep -c '\$' hello.txt) -gt 0 ] && [ $(grep -c ":97A:" hello.txt) -gt 1 ]
then
echo "condition satisfied"
else
echo "condition not satisfied"
fi
For your hello.txt the output will be:
>> bash test.bash
condition not satisfied
Since there's no dollar sign in your file
[ $(grep -c '\$' hello.txt) -gt 0 ]
will test
[ 0 -gt 0 ]
and yield false, while
[ $(grep -c ':97A' hello.txt) -gt 1 ]
will test
[ 2 -gt 1 ]
and yield true. Finally, false && true will yield false and the second echo statement will be executed.
"i'm checking for the existence of $ symbol"
First condition won't match because there is no "$" sign anywhere in your input, therefore output of first grep is 0. As 0 isn't greater than 0, the result is "false". Consequently, the second clause won't be executed at all. "Condition is not satisfied" because your requirement for "satisfied" is: input contains both "$" AND ":97A:".
For a result whether grep matched any line, you don't need to count number of matches.
if grep -q '\$' file; then ...
is a way to use result of grep in a conditional statement without rube-goldbergismns
Using awk and reading the file only once:
if awk '/[$]/{d++} /:97A:/{o++} END{exit !(d && o>1)}' hello.txt; then
echo "condition satisfied"
else
echo "condition not satisfied"
fi
I need to check two variables, count and count1, for equality with 2.
I tried the following code, but it didn't work:
if [ $count -eq 2 || $count1 -eq 2 ]; then
echo "Condition passsed"
fi
How can I fix it?
That type of conditional doesn't recognize ||. You either need to use -o (or), or use a [[ test:
if [ $count -eq 2 -o $count1 -eq 2 ]; then
echo "Condition passsed"
fi
if [[ $count -eq 2 || $count1 -eq 2 ]]; then
echo "Condition passsed"
fi
You need to use [[:
if [[ $count -eq 2 || $count1 -eq 2 ]]; then echo "Condition passsed"; fi