Как отменить тест с регулярными выражениями в скрипте bash?

174

Используя GNU bash (версия 4.0.35 (1) -релиз (x86_64-suse-linux-gnu), я хотел бы отменить тест с регулярными выражениями. Например, я хотел бы условно добавить путь к переменной PATH, если путь еще не существует, как в:

TEMP=/mnt/silo/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if [[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH; else PATH=$PATH:$TEMP; fi
export PATH

Я уверен, что есть миллион способов сделать это, но я хотел бы знать, можно ли как-то отрицать условное условие, как в (ошибочном):

TEMP=/mnt/silo/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/Scripts:
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
TEMP=/mnt/silo/local/bin
if ![[ ${PATH} =~ ${TEMP} ]] ; then PATH=$PATH:$TEMP; fi
export PATH
Дэвид Роджерс
источник

Ответы:

194

Нужно было правильно, просто поставить пробел между !и [[т.п.if ! [[

SiegeX
источник
14
Ой вей! Как раз когда я благополучно обошел межгалактическое безумие специальных персонажей perl, я обнаружил, что теряюсь в пространстве bash (размещение)! (Я чувствую страх, сжимающий мою кишку как питон.) Спасибо!
Дэвид Роджерс
127

Вы также можете поставить восклицательный знак внутри скобок:

if [[ ! $PATH =~ $temp ]]

но вы должны закрепить свой шаблон, чтобы уменьшить количество ложных срабатываний:

temp=/mnt/silo/bin
pattern="(^|:)${temp}(:|$)"
if [[ ! "${PATH}" =~ ${pattern} ]]

который ищет совпадение в начале или конце с двоеточием до или после него (или обоих). Я рекомендую использовать строчные или смешанные имена переменных как привычку, чтобы уменьшить вероятность конфликтов имен с переменными оболочки.

Приостановлено до дальнейшего уведомления.
источник
Ах, спасибо за напоминание о закреплении. Идея использования строчных или смешанных имен переменных вводит в заблуждение новичка в bash, поскольку совет, который я видел до сих пор, заключается в использовании заглавных букв. Я понимаю, что вы делаете, но я не видел достаточно примеров сценариев bash, чтобы чувствовать себя комфортно, отклоняясь от (моего понимания) поваренной книги.
Дэвид Роджерс
4
@anyoneis доверяют нам в этом. Следует избегать использования пользовательских переменных верхнего регистра. Все переменные в bash расширены, $поэтому нет смысла их вводить в верхнем регистре, чтобы они выделялись.
SiegeX
Я нахожу if [[ ! $foo =~ bar ]]более безопасным, чем if ! [[ $foo =~ bar ]], потому что это облегчает введение большего количества условий дляif
CTodea
19

самый безопасный способ это поставить! для отрицания регулярного выражения в [[ ]]следующем виде:

if [[ ! ${STR} =~ YOUR_REGEX ]]; then

в противном случае это может произойти сбой в некоторых системах.

не суй нос
источник
9

Да, вы можете отменить тест, как уже указывал SiegeX .

Однако вы не должны использовать регулярные выражения для этого - он может потерпеть неудачу, если ваш путь содержит специальные символы. Попробуйте это вместо:

[[ ":$PATH:" != *":$1:"* ]]

(Источник)

Марк Байерс
источник
1
Еще одна причина использовать эту форму в том, что она не будет случайно соответствовать подстрокам (например, не удастся добавить «/ bin» к пути, потому что «/ usr / bin» уже существует).
Гордон Дэвиссон
Мне потребовалось некоторое время, чтобы понять, как двоеточия слева дали мне якорь, который я хотел. Стоит запомнить идею сокращения шаблона путем добавления материала к искомой строке. Я не понимаю, почему специальные символы в пути могут нарушить решение регулярных выражений, но не решение шаблона bash. Можете привести пример?
Дэвид Роджерс
Я не думаю, что это будет работать надежно во всех случаях. Соответствие регулярному выражению в превосходном ИМХО
Фелипе Альварес
5

Мне нравится упрощать код без использования условных операторов в таких случаях:

TEMP=/mnt/silo/bin
[[ ${PATH} =~ ${TEMP} ]] || PATH=$PATH:$TEMP
Dimir
источник