Bash: выражение [[ ]] vs (( )) in =~ для сценария if then. Также значение =~ ^

В bash man указан оператор =~ под [[ выражение ]], а для выражений я должен использовать закрытые скобки. Это также принятый ответ здесь:

(Двойные квадратные скобки обязательны) «потому что =~ является оператором составной команды [[ expression ]]».

Однако моя строка сценария с =~ не работает с закрытыми скобками, но работает с открытыми скобками. Я хотел бы знать, что Bash делает как в открытых, так и в закрытых скобках, чтобы лучше понять, как они работают.


контекст

Я хотел бы перенести файлы из $R/x/ в ppc/, где $R — это число, относящееся к 30 каталогам, их метки варьируются от 2,0 до 5,0 с шагом 0,1.

x/ — это общая метка подкаталога в $R.

Каждая 5-я директория, то есть: (2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0) Мне нужно приложить условие, чтобы скрипт вытягивал только определенные файлы из x/, а остальные оставлял позади. Все эти файлы начинаются с 105 и извлекаются с $R/x/105*.

Мой скрипт работает следующим образом:

#!/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

Так что это работает нормально. Я просто получаю список ошибок при запуске скрипта для каждого значения $R от 2,0 до 5,0, например, для $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)$ ")

но конечный результат вывода в /ppc именно то, что я хотел. Я перевел все 30 каталогов из $R = 2.0 в $R = 5.0, и в каждом пятом каталоге я выборочно подтягивал определенные файлы.


Однако, если я изменю свое условие «если» на:

if [[ $R =~ ^(2.0|2.5|3.0|3.5|4.0|4.5|5.0)$ ]] ;
   ^^                                       ^^

т.е. закрытые скобки, я получаю ноль сообщений об ошибках; однако без арифметики мой вывод идет в дерьмо. Вывод такой, как если бы мой скрипт был написан вообще без условия if/then:

#!/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/

так что просто прямое копирование без условий, только почему-то у меня также нет каталога 2.0 в ppc/, поэтому первый $R не может полностью вычислиться.


Вопросы

  • Почему bash обрабатывает условие «если» как арифметическое, а не, скажем, как текстовые строки? Будут ли мне всегда нужны открытые круглые скобки всякий раз, когда у меня есть число, даже если руководство помечает его как выражение с закрытой скобкой?
  • Как Bash интерпретирует условие «если» с закрытыми скобками? Мне интересно, как я получил результат, который я сделал. Я не верю, что он полностью игнорировал условие if, потому что каталог 2.0 не печатался.
  • Почему я получаю эти ошибки с открытыми скобками? Могу ли я это исправить?
  • Дополнительный вопрос: ^ в

    =~ ^(

    означает "не равно", это правильно? Как бы в нем функционировали типа "!=~", если бы этот оператор существовал? В мануале не нашел его значения. Я скопировал эту команду из онлайна в стек. Насколько я понимаю, если я оставлю ^, скрипт будет искать =, а не !=

Благодарю вас!


person Blaisem    schedule 16.02.2017    source источник
comment
Вычисление регулярных выражений с использованием =~ поддерживается только в [[ ... ]], и хотя ваше регулярное выражение не совсем корректно, оно должно работать для заданного диапазона i в цикле for.   -  person anubhava    schedule 16.02.2017
comment
Я предлагаю потратить некоторое время на чтение справочной страницы. (( ... )) — это команда только для арифметических выражений. ^, следующий за =~, является просто якорем начала строки в регулярном выражении.   -  person chepner    schedule 16.02.2017
comment
Маркер, следующий за if, является командой и приравнивается к True, если команда выполнена успешно (т. е. если она имеет возвращаемое значение, равное нулю). Скобки, [[, (( или [ — это разные команды. [[ в основном используется для сопоставления текстовых шаблонов, а (( — для арифметики. [ — это старая команда test оболочки Bourne.   -  person cdarke    schedule 16.02.2017
comment
Пожалуйста, спрашивайте только об одном. Пожалуйста, прочитайте страницы справочного центра о том, как задавать вопросы здесь, в Stack Overflow.   -  person AdrianHHH    schedule 16.02.2017
comment
Спасибо за ответы. @anubhava Я понимаю, что =~ для [[ ... ]]. Вот почему мне любопытно, почему (( ... )) работает. &chepner Спасибо за пояснение по ^; Я думал, что это может быть так. Как уже упоминалось, я знаю, что (( ... )) используется только для арифметических выражений. Почему это работает для оператора, который, как указано в руководстве, строго [[ ... ]]? &cdarke Мой скрипт работает как !~ насколько я понимаю? Это смутило меня, потому что в руководстве указано, что =~ предназначено для сопоставления выражений, а не наоборот. Вы знаете, почему это работает как !~ ?   -  person Blaisem    schedule 16.02.2017
comment
@AdrianHHH Извините за несколько вопросов. Тогда предпочтительнее скопировать + вставить репост этого 4 раза? Меня устраивает любой протокол.   -  person Blaisem    schedule 16.02.2017
comment
@cdarke !~ не в bash..   -  person Grisha Levit    schedule 17.02.2017