Bash conditional assignment that tests a variable whilst building a string - bash

I found this question for how to do conditional assignment in bash, but what I'm trying to do is a little more complex, and I can't seem to get the syntax right. The condition in my case is to test a variable to see if it exists, and the output is concatenated to a string.
Here's what I have so far:
fwversion="${BASH_REMATCH[1]}.$(( [[ BASH_REMATCH[2] ]] ? BASH_REMATCH[2] : 0 ))"
Which produces this error message:
bash: line 41: [[ BASH_REMATCH[2] ]] ? BASH_REMATCH[2] : 0 : syntax error:
operand expected (error token is "[[ BASH_REMATCH[2] ]] ? BASH_REMATCH[2] : 0 ")
Here's what I'm trying to achieve as C++ code:
std::string fwversion = BASH_REMATCH[1] + "." + ((BASH_REMATCH[2]) ? : BASH_REMATCH[2] : 0);
What's the correct syntax to do this in bash? Thanks.

Looks like [[ ... ]] are not understood in an arithmetic expression.
I'd do this:
fwversion=${BASH_REMATCH[1]}
[[ ${BASH_REMATCH[2]} ]] && fwversion+=${BASH_REMATCH[2]} || fwversion+=0
or
[[ ${BASH_REMATCH[2]} ]] && ext=${BASH_REMATCH[2]} || ext=0
fwversion="${BASH_REMATCH[1]}.$ext"
On second thought, I wouldn't do that at all, I'd use the power of the shell's parameter expansion
str="foo:bar"
if [[ $str =~ ^([a-z]+):([a-z]*)$ ]]; then
echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]:-0}"
fi
foo.bar
str="foo:"
if [[ $str =~ ^([a-z]+):([a-z]*)$ ]]; then
echo "${BASH_REMATCH[1]}.${BASH_REMATCH[2]:-0}"
fi
foo.0

Related

Conditional binary operator expected: syntax error near `$1' [duplicate]

This question already has answers here:
Why should there be spaces around '[' and ']' in Bash?
(5 answers)
Closed 4 years ago.
I am trying to run simple code block.
It gives error on fourth line as "syntax error near `$1'"
=~ means Matches Regular Expression
How should I use '$1' variable with this operator?
Here is my code:
if [[ $1 -gt 3 ]] && [[ $1 -lt 7 ]]
then
echo "$1 is between 3 and 7"
elif [[ $1 =~ "Jeff"]] || [[ $1 =~ "Roger" ]] || [[ $1 =~ "Brian" ]]
then
echo "$1 works in the Data Science Lab"
else
echo "You entered: $1, not what I was looking for.."
fi
Very funny indeed. You've typed the first condition in that line as [[ $1 =~ "Jeff"]], so without a space between "Jeff" and ]] bash interprets them as a single string, which is obviously not your pattern, and the whole parse fails and line structure crashes. If you add that space:
if [[ $1 =~ "Jeff" ]] || [[ $1 =~ "Roger" ]] || [[ $1 =~ "Brian" ]]
then it works... seemingly...

Bash if variable is an integer

I'm trying to write an if statement in bash that will exit if the variable supplied is not an integer. I will eventually be nesting this if statement within a while loop.
When I do run this I am getting an syntax error.
#!/bin/bash
if [ $f1 != ^[0-9]+$ ]
then
exit 1
fi
I have always like the integer test using the equality test construct:
[ $var -eq $var 2>/dev/null ] || exit 1
If var is not an integer, the equality fails due to the error generated. It is also POSIX compliant as it doesn't rely on character classes or the bash [[ construct.
You better negate the condition like this:
if [[ ! "$f1" =~ ^[0-9]+$ ]]; then
exit 1
fi
note the [[ and ]] syntax for the regular expressions, together with ! to negate it. Then, we use =~ for regexs.
Test
$ r=23a
$ [[ ! "$r" =~ ^[0-9]+$ ]] && echo "no digit" || echo "digit"
no digit
$ r=23
$ [[ ! "$r" =~ ^[0-9]+$ ]] && echo "no digit" || echo "digit"
digit

Regarding Bash substring comparison

I try to test if a string starts with a certain prefix. But my script seems not work (I would expect the "if" branch will not get run). Can some Bash expert help to take a look? thanks!
Here is my code and test result:
$ cat testb.bash
#!/bin/bash
my_var="abcdefg";
if [[ "${my_var:0:5}"=="order" ]]; then
echo "value of my_var is ${my_var}.";
fi;
if [[ "${my_var:0:5}" -eq "order" ]]; then
echo "value of my_var is ${my_var}.";
fi;
if [ "${my_var:0:5}"="order" ]; then
echo "value of my_var is ${my_var}.";
fi;
$ bash -x testb.bash
+ my_var=abcdefg
+ [[ -n abcde==order ]]
+ echo 'value of my_var is abcdefg.'
value of my_var is abcdefg.
+ [[ abcde -eq order ]]
+ echo 'value of my_var is abcdefg.'
value of my_var is abcdefg.
+ '[' abcde=order ']'
+ echo 'value of my_var is abcdefg.'
value of my_var is abcdefg.
$
Whitespace is significant in this case. As you can see in the -x output, it understands the first condition as
[[ -n "${my_var:0:5}==order" ]]
Moreover, to test for a prefix, you can use a pattern:
[[ $my_var == order* ]]
To test the existence of substring, you can use either of these:
if [[ "$j" =~ string1 ]]; then
if [[ $j == *string1* ]]; then
In your particular case, you miss a space surounding ==, so instead of
if [[ "${my_var:0:5}"=="order" ]]; then
it should be
if [[ "${my_var:0:5}" == "order" ]]; then
^ ^
Finally, note that your condition was evaluated as true because it was evaluating if [ "string" ], which is true if string is not empty:
$ [ "a" ] && echo "yes"
yes
Test
$ cat a
#!/bin/bash
my_var="abcdefg";
if [[ "${my_var:0:5}" == "order" ]]; then
echo "value of my_var is ${my_var}."
elif [[ "${my_var:0:5}" == "abcde" ]]; then
echo "yeahaa"
else
echo "is not"
fi
$ ./a
yeahaa
Ok, i tested your code, you shoud such as the following code:
prefix="pre_order";
pre="pre_"
len=${#pre}
echo $len
if [[ "${prefix:0:len}" == "blahvlah" ]] ; then
echo "dddd"
fi;
Notes:
use == for string comparation
for ${} you should initilize a string variable before ${}
use len=${#pre} for lenght of string.
A POSIX-compliant way to test for a prefix is to attempt to remove the prefix, and compare the result to the original string. If the two are the same, the prefix is not present, the removal fails, and the expression expands to the original string.
prefix=foo
string=foobar
if [ "${string#$prefix}" = "$string" ]; then
printf "$string does not start with $prefix\n"
else
printf "$string starts with $prefix\n"
fi

Bash, if's, reusing variables

if [[ $line == *"option 1"* ]]
then
CURRENT_OPTION=1
fi
if [[ $line == *"option 2"* ]]
then
CURRENT_OPTION=2
fi
if [[ $line =~ "What i want" ]]
then
if [[ $CURRENT_OPTION -eq 1 ]]
then
MEM1=$(awk '/Used heap/ { gsub(/M/, " "); print $4 }')
elif [[ $CURRENT_OPTION -eq 2 ]]
then
MEM2=$(awk '/Used heap/ { gsub(/M/, " "); print $4 }')
fi
fi
Because CURRENT_OPTION is defined within an if, its value is not correct when checked in the third if. How do I pass it out so that it is?
Just declare CURRENT_OPTION at the top, something like:
declare -i CURRENT_OPTION=0
i to declare it as an int.
In all of your if statements you should enclose the variables in double quotes. If the variable is an empty string (or if the variable doesn't exist) then the if statement will not contain enough arguments and will throw an error.
Here is an example:
if [[ $var -eq 1 ]]
then
echo yes
else
echo no
fi
If var is uninitialised, bash will expand the statement to look like this:
if [[ -eq 1 ]]
then
echo yes
else
echo no
fi
There are not enough arguments to make the if statement valid here, and bash will throw an error:
bash: conditional binary operator expected
bash: syntax error near `1'
By wrapping the variable in quotes, this situation is avoided. This statement:
if [[ "$var" -eq 1 ]]
...
is expanded to:
if [[ "" -eq 1 ]]
...
and now the if statement has enough arguments (the first one being an empty string) to parse.

How do you compare a string containing an angle bracket '<' in bash?

The following bash script is giving me problems:
#!/bin/bash
if [[ $VAR -eq "<EMPTY>" ]]; then echo "Hello World!"; fi
Bash fails, complaining:
line 3: [[: <EMPTY>: syntax error: operand expected (error token is "<EMPTY>")
How can I test if the string contained in VAR is equivalent to the string "<EMPTY>"?
You are using the wrong operator. == is for strings, -eq is for numbers.
#!/bin/bash
if [[ $VAR == "<EMPTY>" ]]; then echo "Hello World!"; fi
Inside [[ ... ]], -eq has a different meaning: it is used to compare integers. You can use (( ... )) to compare integeres with normal operators, though. Use the following for strings:
[[ $VAR == "<EMPTY>" ]]

Resources