В 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 не печатался.
- Почему я получаю эти ошибки с открытыми скобками? Могу ли я это исправить?
Дополнительный вопрос:
^
в=~ ^(
означает "не равно", это правильно? Как бы в нем функционировали типа "!=~", если бы этот оператор существовал? В мануале не нашел его значения. Я скопировал эту команду из онлайна в стек. Насколько я понимаю, если я оставлю
^
, скрипт будет искать =, а не !=
Благодарю вас!
=~
поддерживается только в[[ ... ]]
, и хотя ваше регулярное выражение не совсем корректно, оно должно работать для заданного диапазонаi
в циклеfor
. - person anubhava   schedule 16.02.2017(( ... ))
— это команда только для арифметических выражений.^
, следующий за=~
, является просто якорем начала строки в регулярном выражении. - person chepner   schedule 16.02.2017if
, является командой и приравнивается к True, если команда выполнена успешно (т. е. если она имеет возвращаемое значение, равное нулю). Скобки,[[
,((
или[
— это разные команды.[[
в основном используется для сопоставления текстовых шаблонов, а((
— для арифметики.[
— это старая командаtest
оболочки Bourne. - person cdarke   schedule 16.02.2017!~
не в bash.. - person Grisha Levit   schedule 17.02.2017