Як я заперечую тест з регулярними виразами в скрипті bash?


173

Використовуючи GNU bash (версія 4.0.35 (1) -release (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

Відповіді:


193

Потрібно було правильно, просто поставити пробіл між !і [[т.п.if ! [[


14
Ой вей! Тільки-но, коли я сміливо проходжу міжгалактичне божевілля спеціального персонажа перла, я опиняюсь втраченим у просторі (розміщення)! (Я відчуваю страх стискати мою кишку, як пітон.) Дякую!
Девід Роджерс

126

Ви також можете поставити знак оклику всередині дужок:

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

але вам слід прив’язати свою модель, щоб зменшити помилкові позитиви:

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

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


Ах, дякую за нагадування про прив’язку. Ідея використання імен малої чи змішаної змінної ініціює бентежа для початківця, оскільки порада, яку я бачив до цього часу, - це використовувати великі регістри. Я розумію, що ви дотримуєтесь, але я не бачив достатньо прикладів сценаріїв, щоб відчувати себе комфортно відхиляючись від (мого розуміння) кулінарної книги.
Девід Роджерс

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.