I have been creating to assign the output of if/else to a variable but keep on getting an error.
For Example:
mathstester=$(If [ 2 = 2 ]
Then echo equal
Else
echo "not equal"
fi)
So whenever I add $mathstester in a script, laid out like this:
echo "Equation: $mathstester"
It should display:
Equation: Equal
Do I need to lay it out differently? Is it even possible?
Putting the if statement in the assignment is rather clumsy and easy to get wrong. The more standard way to do this is to put the assignment inside the if:
if [ 2 = 2 ]; then
mathstester="equal"
else
mathstester="not equal"
fi
As for testing variables, you can use something like if [ "$b" = 2 ] (which'll do a string comparison, so for example if b is "02" it will NOT be equal to "2") or if [ "$b" -eq 2 ], which does numeric comparison (integers only). If you're actually using bash (not just a generic POSIX shell), you can also use if [[ "$b" -eq 2 ]] (similar to [ ], but with somewhat cleaner syntax for more complicated expressions), and (( b == 2 )) (these do numeric expressions only, and have very different syntax). See BashFAQ #31: What is the difference between test, [ and [[ ? for more details.
The correct way to use if is:
mathtester=$(if [ 2 = 2 ]; then echo "equal"; else echo "not equal"; fi)
For using this in multiline statements you might consider looking link.
Related
I cannot figure out how to use a simple if/elif/else structure in bash. I cannot believe how something as trivial as that can be so unintuitive and difficult. I've already spent quite a bit of time fiddling around with that. What I want to do is something like that:
aaa="xxx"
if [[ $aaa -eq "bbb" ]]; then
echo "bbb"
elif [[ $aaa -eq "ccc" ]]; then
echo "ccc"
else
echo "something else"
fi
I've tried it with a single [, with two [[, with ((, with == instead of -eq, I'm really not a Linux guy and very confused about the syntax, I've seen all kinds of different syntaxes regardind if conditionals.
It always prints bbb, no matter what value aaa has.
Can somebody please explain to me how to do this so that it works?
-eq is for numeric comparison only, for more info consider reading:
Shell equality operators (=, ==, -eq)
Also, consider quoting the variables:
When to wrap quotes around a shell variable?
Changed -eq to ==:
Quoted the variables
#!/bin/bash
aaa="xxx"
if [[ "$aaa" == "bbb" ]]; then
echo "bbb"
elif [[ "$aaa" == "ccc" ]]; then
echo "ccc"
else
echo "something else"
fi
something else
Try it online!
Use -eq for numeric comparisons, not for strings. Also, you are using quotes incorrectly. Use double quotes to prevent field splitting when you expand variables. IOW, they are needed around variables, but not around literal strings (unless the literal string contains whitespace or characters that would be interpreted by the shell such as a backtick or a $, etc.). And don't use a string of if/else when a case statement is more appropriate. Overall:
#!/bin/sh
aaa="$1"
if [ "$aaa" = bbb ]; then
echo "bbb"
elif [ "$aaa" = ccc ]; then
echo "ccc"
else
echo "something else"
fi
case $aaa in
bbb) echo bbb;;
ccc) echo ccc;;
*) echo something else;;
esac
Regarding quotes: there is absolutely nothing wrong with using quotes as in if [ "$aaa" = "bbb" ]; or case "$aaa" in, but it is almost always a mistake to omit them as in if [ $aaa = "bbb" ] Omitting the quotes in case $aaa in or var=$aaa is allowed because field splitting does not happen in those cases, but it is certainly best practice to include the quotes in those cases. Generally, use quotes around varaibles. if [ $aaa = "bbb" ] is a huge source of potential bugs, and should be avoided.
Bash shell, the following code snippet results in the error: "too many arguments". I have searched thoroughly and cannot get to the bottom of this.
if [ [ $i % 3 ] == 0 ] && [ [ $i % 5 == 0 ] ]
I am just learning bash, any help is much appreciated, thanks in advance!
Solved: if [[ $((i % 3)) == 0 && $((i % 5)) == 0 ]] thank you #BroSlow
You can simplify this by using an arithmetic expression:
if (( i % 3 == 0 && i % 5 == 0 )); then
(or even more simply, with (( i % 15 == 0 ))...).
Let me explain this a little more: in bash there are four main types of conditions you'll see in an if command:
[ ... ] -- the [ and ] look like a some kind of parentheses, but [ is actually a synonym for the test command, and evaluates its arguments as a conditional expression. It does not understand additional [ ] pairs as parentheses, you have to use ( ) instead. But because it's a command, all of its arguments are subject to the usual shell parsing before being handed to the command, and so you'd have to escape them like \( ... \), which is annoying. And you can't use && because that separates commands, you have to use -a instead.
And there are a pile of other parsing oddities, like if you use < or > you have to escape them or it'll treat them as input/output redirects. Seriously, if you use if [ 3 > 5 ], it'll create a file named "5", and dump the output of the command [ 3 ] into it. And BTW [ 3 ] doesn't output anything, but it does return success (i.e. true) because "3" is not blank...
Basically, you should not use [ ... ] unless you need compatibility with generic shells that don't support any of the better options.
[[ ... ]] -- this is a bash conditional expression, which is basically a cleaned up version of [ ... ] (aka test), with the weird parsing oddities removed and some cool additional features added. You can use parentheses (not brackets) for grouping, and < and > for comparison, all without escapes. If you're using bash (not a generic shell), this is usually the way to go. But it doesn't do math (it's all string-oriented), unless you force arithmetic evaluation of something with $(( )) (as in BroSlow's answer).
And a warning: in [[ ... ]], =, !=, <, and > do string comparisons, not arithmetic. For example, [[ 05 = 5 ]] is false, because they aren't textually equal. And [[ 10 > 5 ]] is also false, because "1" comes before "5" alphabetically (well, in standard sorting order). If you want arithmetic comparisons here, you need to use -eq, -ne, -lt, and -gt instead.
(( ... )) -- this is an arithmetic expression. Sort of similar to [[ ]], except the contents get evaluated as a mathematical expression instead of string-oriented tests. Note that in a math context, variables get evaluated automatically, so you can use i instead of $i. Also, = is an assignment, while == is a comparison (in [[ ... ]], they're both comparisons).
This is confusingly similar to the $(( ... )) thing I mentioned in the last item. The difference is that (( ... )) acts like an entire command on its own, while $(( ... )) evaluates the contents and returns the result for inclusion in some other command. For example, echo $((3+5)) will evaluate to echo 8, which then prints "8".
Some other command. You can use any command you want as the test in an if statement, and if will execute the then or else branch based on whether the command succeeds or fails. You'll see things like if grep somepattern somefile; then... and if somecommand; then echo "it worked"; else echo "it failed"; fi, and such. All of the other three options are really just special cases of this: you can use [ ...], [[ ... ]], or (( ... )) anyplace you'd use any other command in bash, they just happen to be particularly useful as if conditions.
You can't nest brackets inside of brackets in bash. So [[ ]] is fine [ ] is fine but [ [ ] ] is not (it assumes the nested brackets are operators). And if you want some math you can do $((math))
Should be
if [[ $((i % 3)) == 0 && $((i % 5)) == 0 ]]
Also see
Too many arguments error in bash
you cannot have space between [ and next [. Change [ [ to [[. Same with ] ].
See Conditional expressions in bash.
I am trying to make a bash script with the output based on the input.
My code looks like this:
#!/bin/bash
echo "Letter:"
read a
if a=3
then
echo "LOL"
fi
if a=4
then
echo "ROFL"
fi
But when I enter 3 or 4, I get both LOL and ROFL.
Is there a way for me to get LOL for 3 and ROFL for 4?
Sorry if I'm using incorrect terms and stuff, I'm new to bash scripting.
In bash, a=3 is an assignment, not a test. Use, e.g.:
if [ "$a" = 3 ]
Inside [...], the equal sign tests for string (character) equality. If you want to test for numeric value instead, then use '-eq` as in:
if [ "$a" -eq 3 ]
The quotes around "$a" above are necessary to avoid an "operator" error when a is empty.
bash also offers a conditional expressions that begin with [[ and have a different format. Many like the [[ format better (it avoids, for example, the quote issue mentioned above) but the cost is loss of compatibility with other shells. In particular, note that dash, which is the default shell (/bin/sh) for scripts under Debian-derived distributions, does not have [[.
Bash thinks you're trying to assign a variable by saying a=3. You can do the following to fix this:
Use the = operator whilst referencing the variable with a $, like so: if [[ $a = 3 ]]
Use the -eq operator, which is special and doesn't require you to reference the variable with a $, but may not be compatible with all sh-derived shells: if [[ a -eq 3 ]]. If you wish to use -eq without Bash reference the variable: if [[ $a -eq 3 ]]
Note:
The double square brackets [[ ... ]] are a preferred format with specifically Bash conditionals. [ ... ] is good with any sh-derived shell (zsh, tcsh, etc).
if a=3 will assign value 3 to variable a
unless a is readonly variable, if a=3 always returns TRUE
same for if a=4
To compare variable a with a value, you can do this if [ $a = 3 ]
so the script should change to
#!/bin/bash
echo "Letter:"
read a
if [ $a = 3 ]
then
echo "LOL"
fi
if [ $a = 4 ]
then
echo "ROFL"
fi
Since a is read from user input, there is possibility user key in:
non numeric value
a string with empty space
nothing, user may just press Enter key
so a safer way to check is:
if [ "x$a" = "x3" ]
I'm trying to delete a large amount of files from my computer, and I'm trying to write a bash script to do so using the rm command. What I want to know is how to do equality in bash, and why my code (posted below) won't compile. Thank you for your help!
#!/bin/bash
# int-or-string.sh
b="0000"
c="linorm"
f=500
e1=2
e2=20
e3=200
e4=2000
for i in {0..10000}
do
a=$(($f*$i))
if ["$i" -eq "$e1"]
then
b="000"
echo $b$
fi
if ["$i" -eq "$e2"]
then
b='00'
fi
if ["$i" -eq "$e3"]
then
b='0'
fi
if ["$i" -eq "$e4"]
then
b =''
fi
if [bash$ expr "$i" % "$e3$ -ne 0]
then
d = $b$c$a
rm d
fi
done
Shell scripts aren't compiled at all.
You need spaces after your [ and before your ].
if [ "$i" -eq "$e1" ]
There's an errant bash$ in there you probably don't want at all. It should probably be a $() operator:
if [ $(expr "$i" % "$e3") -ne 0 ]
You can't have spaces around the = in bash. For example, change b ='' to b='' and d = $b$c$a to d=$b$c$a.
echo $b$ looks like it should be echo $b.
Shell script does not compile it is a scripting language.
Try to fix this line :
if [bash$ expr "$i" % "$e3$ -ne 0]
Make it like below :
if [ $(expr "$i" % "$e3$") -ne 0 ]
You need spaces around the square brackets. The [ is actually a command, and like all commands needs to be delineated by white space.
When you set values for variables in shell, you do not put spaces around the equals signs.
Use quotation marks when doing comparisons and setting values to help delineate your values.
What happens if none of the if conditions are true, and $b isn't set.
What is the logic behind this code. It seems to be a bunch of random stuff. You're incrementing $ from 1 to 10000, but only setting the value of $b on only four of those values. Every 200 steps, you delete a file, but $b may or may not be set even though it's part of the file name.
Did you write this program yourself? Did you try to run it? What errors were you getting? Did you look at the lines referenced by those errors. It looks like you included the bash$ prompt as part of the command.
There were plenty of errors, and I've cleaned most of them up. The cleaned up code is posted below, but it still doesn't mean it will do what you want. All you said is you want to delete "a large amount of files" on your computer, but gave no other criteria. You also said "What I want to know is how to do equality in bash" which is not the question you stated in you header.
Here's the code. Note the changes, and it might lead to whatever answer you were looking for.
#!/bin/bash
# int-or-string.sh
b="0000"
c="linorm"
f=500
e1=2
e2=20
e3=200
e4=2000
for i in {0..10000}
do
a=$(($f*$i))
if [ "$i" -eq "$e1" ]
then
b="000"
elif [ "$i" -eq "$e2" ]
then
b='00'
elif [ "$i" -eq "$e3" ]
then
b='0'
elif [ "$i" -eq "$e4" ]
then
b=''
fi
if ! $(($i % $e3))
then
d="$b$c$a"
rm "$d"
fi
done
ERRORS:
Spaces around the [ and ]
The rm "$d" command was originallyrm dwhich would just remove a file namedd`.
if/then statement converted to if/else if.
Rewrote [ $(expr "$1" % "$e3") -ne 0 ].
No need for expr since BASH has $((..)) syntax.
No need for test command ([) since if automatically evaluates zero to true and non-zero to false.
Added quotes.
I couldn't find any one simple straightforward resource spelling out the meaning of and fix for the following BASH shell error, so I'm posting what I found after researching it.
The error:
-bash: [: too many arguments
Google-friendly version: bash open square bracket colon too many arguments.
Context: an if condition in single square brackets with a simple comparison operator like equals, greater than etc, for example:
VARIABLE=$(/some/command);
if [ $VARIABLE == 0 ]; then
# some action
fi
If your $VARIABLE is a string containing spaces or other special characters, and single square brackets are used (which is a shortcut for the test command), then the string may be split out into multiple words. Each of these is treated as a separate argument.
So that one variable is split out into many arguments:
VARIABLE=$(/some/command);
# returns "hello world"
if [ $VARIABLE == 0 ]; then
# fails as if you wrote:
# if [ hello world == 0 ]
fi
The same will be true for any function call that puts down a string containing spaces or other special characters.
Easy fix
Wrap the variable output in double quotes, forcing it to stay as one string (therefore one argument). For example,
VARIABLE=$(/some/command);
if [ "$VARIABLE" == 0 ]; then
# some action
fi
Simple as that. But skip to "Also beware..." below if you also can't guarantee your variable won't be an empty string, or a string that contains nothing but whitespace.
Or, an alternate fix is to use double square brackets (which is a shortcut for the new test command).
This exists only in bash (and apparently korn and zsh) however, and so may not be compatible with default shells called by /bin/sh etc.
This means on some systems, it might work from the console but not when called elsewhere, like from cron, depending on how everything is configured.
It would look like this:
VARIABLE=$(/some/command);
if [[ $VARIABLE == 0 ]]; then
# some action
fi
If your command contains double square brackets like this and you get errors in logs but it works from the console, try swapping out the [[ for an alternative suggested here, or, ensure that whatever runs your script uses a shell that supports [[ aka new test.
Also beware of the [: unary operator expected error
If you're seeing the "too many arguments" error, chances are you're getting a string from a function with unpredictable output. If it's also possible to get an empty string (or all whitespace string), this would be treated as zero arguments even with the above "quick fix", and would fail with [: unary operator expected
It's the same 'gotcha' if you're used to other languages - you don't expect the contents of a variable to be effectively printed into the code like this before it is evaluated.
Here's an example that prevents both the [: too many arguments and the [: unary operator expected errors: replacing the output with a default value if it is empty (in this example, 0), with double quotes wrapped around the whole thing:
VARIABLE=$(/some/command);
if [ "${VARIABLE:-0}" == 0 ]; then
# some action
fi
(here, the action will happen if $VARIABLE is 0, or empty. Naturally, you should change the 0 (the default value) to a different default value if different behaviour is wanted)
Final note: Since [ is a shortcut for test, all the above is also true for the error test: too many arguments (and also test: unary operator expected)
Just bumped into this post, by getting the same error, trying to test if two variables are both empty (or non-empty). That turns out to be a compound comparison - 7.3. Other Comparison Operators - Advanced Bash-Scripting Guide; and I thought I should note the following:
I used -e thinking it means "empty" at first; but that means "file exists" - use -z for testing empty variable (string)
String variables need to be quoted
For compound logical AND comparison, either:
use two tests and && them: [ ... ] && [ ... ]
or use the -a operator in a single test: [ ... -a ... ]
Here is a working command (searching through all txt files in a directory, and dumping those that grep finds contain both of two words):
find /usr/share/doc -name '*.txt' | while read file; do \
a1=$(grep -H "description" $file); \
a2=$(grep -H "changes" $file); \
[ ! -z "$a1" -a ! -z "$a2" ] && echo -e "$a1 \n $a2" ; \
done
Edit 12 Aug 2013: related problem note:
Note that when checking string equality with classic test (single square bracket [), you MUST have a space between the "is equal" operator, which in this case is a single "equals" = sign (although two equals' signs == seem to be accepted as equality operator too). Thus, this fails (silently):
$ if [ "1"=="" ] ; then echo A; else echo B; fi
A
$ if [ "1"="" ] ; then echo A; else echo B; fi
A
$ if [ "1"="" ] && [ "1"="1" ] ; then echo A; else echo B; fi
A
$ if [ "1"=="" ] && [ "1"=="1" ] ; then echo A; else echo B; fi
A
... but add the space - and all looks good:
$ if [ "1" = "" ] ; then echo A; else echo B; fi
B
$ if [ "1" == "" ] ; then echo A; else echo B; fi
B
$ if [ "1" = "" -a "1" = "1" ] ; then echo A; else echo B; fi
B
$ if [ "1" == "" -a "1" == "1" ] ; then echo A; else echo B; fi
B
Another scenario that you can get the [: too many arguments or [: a: binary operator expected errors is if you try to test for all arguments "$#"
if [ -z "$#" ]
then
echo "Argument required."
fi
It works correctly if you call foo.sh or foo.sh arg1. But if you pass multiple args like foo.sh arg1 arg2, you will get errors. This is because it's being expanded to [ -z arg1 arg2 ], which is not a valid syntax.
The correct way to check for existence of arguments is [ "$#" -eq 0 ]. ($# is the number of arguments).
I also faced same problem. #sdaau answer helped me in logical way. Here what I was doing which seems syntactically correct to me but getting too many arguments error.
Wrong Syntax:
if [ $Name != '' ] && [ $age != '' ] && [ $sex != '' ] && [ $birthyear != '' ] && [ $gender != '' ]
then
echo "$Name"
echo "$age"
echo "$sex"
echo "$birthyear"
echo "$gender"
else
echo "Enter all the values"
fi
in above if statement, if I pass the values of variable as mentioned below then also I was getting syntax error
export "Name"="John"
export "age"="31"
export "birthyear"="1990"
export "gender"="M"
With below syntax I am getting expected output.
Correct syntax:
if [ "$Name" != "" -a "$age" != "" -a "$sex" != "" -a "$birthyear" != "" -a "$gender" != "" ]
then
echo "$Name"
echo "$age"
echo "$sex"
echo "$birthyear"
echo "$gender"
else
echo "it failed"
fi
There are few points which we need to keep in mind
use "" instead of ''
use -a instead of &&
put space before and after operator sign like [ a = b], don't use as [ a=b ] in if condition
Hence above solution worked for me !!!
Some times If you touch the keyboard accidentally and removed a space.
if [ "$myvar" = "something"]; then
do something
fi
Will trigger this error message. Note the space before ']' is required.
I have had same problem with my scripts. But when I did some modifications it worked for me. I did like this :-
export k=$(date "+%k");
if [ $k -ge 16 ]
then exit 0;
else
echo "good job for nothing";
fi;
that way I resolved my problem. Hope that will help for you too.