In bash man, the =~ operator is listed under [[ expression ]], and for expressions I should use closed brackets. This is also an accepted answer here:
(Double square brackets are required) "because
=~
is an operator of the[[ expression ]]
compound command."
However, my script line with =~
fails with closed brackets yet functions with open brackets. I would like to know what Bash is doing in both the open and closed bracket cases so that I might understand better how they function.
context
I would like to transfer files from $R/x/
into ppc/
, where $R
is a number referring to 30 directories, their labels ranging from 2.0 to 5.0 in increments of 0.1
x/
is a generic subdirectory label within $R.
Every 5th directory, ie: (2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0) I need to attach a condition for the script to pull only specific files from x/
and leave the rest behind. These files all begin with 105 and are pulled with $R/x/105*
.
My script works as follows:
#!/bin/bash
#
for (( i=0;i<=30; i++ )) ;
do
R=$(echo "scale=2;2.0+0.1*$i" |bc -l)
#$R specifies a number corresponding to the directory I need
if (( $R =~ ^(2.0|2.5|3.0|3.5|4.0|4.5|5.0)$ )) ;
#This line is important. My question relates solely to this line.
then
cp -r $R/ ppc/
else
mkdir ppc/$R/ &&
mkdir ppc/$R/x &&
cp -r $R/x/105* ppc/$R/x
fi
done
So this works out fine. I just get a list of errors upon running the script for every value of $R
from 2.0 to 5.0, ex for $R = 4.6:
./Script.in: line 11: ((: 4.6 =~ ^(2.0|2.5|3.0|3.5|4.0|4.5|5.0)$ : syntax error: invalid arithmetic operator (error token is ".6 =~ ^(2.0|2.5|3.0|3.5|4.0|4.5|5.0)$ ")
but the end output result in /ppc is exactly what I wanted. I transfered all the 30 directories from $R = 2.0 to $R = 5.0, and every fifth directory I selectively pulled specific files.
However, if I change my "if" condition to:
if [[ $R =~ ^(2.0|2.5|3.0|3.5|4.0|4.5|5.0)$ ]] ;
^^ ^^
ie. closed brackets, I get zero error messages; however without the arithmetic my output goes to shit. The output is as if my script were written with no if/then condition at all:
#!/bin/bash
#
for (( i=0;i<=30; i++ )) ;
do
R=$(echo "scale=2;2.0+0.1*$i" |bc -l)
cp -r $R/ ppc/
done
rm -r ppc/2.0/
so just straight copying with no conditions, only somehow I also have no 2.0 directory in ppc/
, so the first $R fails to compute entirely.
Questions
- Why does bash treat the "if" condition as arithmetic instead of say, text strings? Will I always need open parentheses any time I have a number involved even if the manual labels it as a closed bracket expression?
- How is the "if" condition being interpreted by Bash with closed brackets? I am wondering how I got the result I did. I don't believe it entirely ignored the if condition, because the 2.0 directory did not print.
- Why do I get those errors with the open brackets? Can I fix that?
Side question: the
^
in=~ ^(
means "not equal to," is that correct? As in it functions like "!=~" if that operator existed? I could not find its meaning in the manual. I copied that command from online in stack. My understanding is that if I leave
^
out, the script will look for = rather than !=
Thank you!