В скрипте bash, какая польза от =~ с "" в правой части?

Это часть сценария bash с указанными номерами строк. Я понимаю, как работает getopts в bash, но не могу понять строку 116. if [[ ! " ${FS_OPTIONS[@]} " =~ " $OPTARG " ]]; then часть. Ранее в сценарии было

#!/usr/bin/env bash
FS_OPTIONS=("ubuntu" "busybox")
while getopts "hsf:" opt; do
    case $opt in
        f)
            if [[ ! " ${FS_OPTIONS[@]} " =~ " $OPTARG "  ]]; then
                echo "Unsupported filesystem $OPTARG"
                echo "Use ubuntu/busybox"
                exit -1
            else
                echo "ok!"
                export FILESYSTEM=$OPTARG
            fi
            ;;
    esac
done

ckim@chan-ubuntu:~/testbash$ test3.sh -f ubuntu
ok!
ckim@chan-ubuntu:~/testbash$ test3.sh -f busybox
ok!
ckim@chan-ubuntu:~/testbash$ test3.sh -f ubunt.
Unsupported filesystem ubunt.
Use ubuntu/busybox

Я изменил строку условия на if [[ ! " ${FS_OPTIONS[@]} " =~ $OPTARG ]]; then и вижу, что правая часть считается регулярным выражением. Теперь я вижу

ckim@chan-ubuntu:~/testbash$ test3.sh -f ubunt.
ok!

Это связано с тем, что " " был удален, а аргумент был принят как регулярное выражение.

В руководстве по bash написано

Доступен дополнительный бинарный оператор =~ с таким же приоритетом, как == и !=. Когда он используется, строка справа от оператора считается расширенным регулярным выражением и соответствующим образом сопоставляется (как в регулярном выражении (3)). Возвращаемое значение равно 0, если строка соответствует шаблону, и 1 в противном случае.

Это было задолго до моего вопроса. Мой первый вопрос: из того, что я заметил выше, когда шаблон совпадает, =~ возвращает 1. (до этого было!), в отличие от руководства. Я что-то пропустил?
Мои вторые вопросы: каковы варианты использования оригинала if [[ ! " ${FS_OPTIONS[@]} " =~ " $OPTARG " ]]; then? использовать регулярное выражение? Поскольку у него есть " ", он примет аргумент как строку (не принимая его как регулярное выражение). Есть ли какая-либо польза для =~ с " "?

(it has ! before) as opposed to the manual. Как это "против"? Есть ! expression True if expression is false.
KamilCuk 11.12.2020 14:43

Тем не менее, обратите внимание, что вопросы «почему» о языковом дизайне здесь обычно не по теме; см. meta.stackexchange.com/a/170415/144918

Charles Duffy 11.12.2020 14:45

@KamilCuk Например, когда я дал -f ubuntu, это показывает, что оно совпало (напечатано ok выше). Это означает, что первая часть if ( ! ... =~ ... ) не была взята, а это означает, что часть =~ вернула 1. Поэтому я дал шаблон соответствия, но =~ вернул 1. (в руководстве сказано, что при совпадении возвращается 0). Я что-то пропустил?

Chan Kim 11.12.2020 14:50

(Кстати, exit -1 обычно не имеет смысла в оболочке: статус выхода UNIX представляет собой целое число без знака, поэтому отрицательные числа всегда преобразуются в положительные).

Charles Duffy 11.12.2020 14:51

... кроме того, [[ ! " ${FS_OPTIONS[@]} " =~ " $OPTARG " ]] не лучшая форма. Следует использовать [*] вместо [@] в контексте, где строка не может расширяться до нескольких слов.

Charles Duffy 11.12.2020 14:52

Еще одно замечание: переменные с заглавными буквами используются для имен, определенных спецификацией POSIX или иным образом изменяющих поведение оболочки и других инструментов, определенных POSIX; тогда как имена, содержащие хотя бы один символ нижнего регистра, зарезервированы для использования приложением, и поэтому вы должны использовать их для новых переменных, которые вы определяете сами. См. соответствующую спецификацию на pubs.opengroup.org/onlinepubs/9699919799/basedefs/…, имея в виду, что переменные оболочки и среды имеют общее пространство имен (поскольку установка переменной оболочки перезаписывает любую переменную среды с таким же именем).

Charles Duffy 11.12.2020 15:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
6
112
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Что означает конкретная строка, о которой вы спрашивали?

Разбивка того, что сделано [[ ! " ${FS_OPTIONS[@]} " =~ " $OPTARG " ]]:

  • " ${FS_OPTIONS[@]} " в этом контексте является менее четким эквивалентом " ${FS_OPTIONS[*]} " (поскольку обычное различие между ними будет иметь [@] расширение до нескольких слов, что не является законным в этом контексте). Таким образом, действуя как ${FS_OPTIONS[*]}, мы расширяемся до полного списка слов в FS_OPTIONS с добавлением разделителя (первый символ в IFS, по умолчанию один пробел). Также обратите внимание, что мы добавляем пробелы в начале и в конце (чтобы наш OPTARG можно было сопоставить в этих позициях, а не только в середине).
  • " $OPTARG " дополняет искомую строку пробелами с обеих сторон, поэтому мы не можем сопоставить подстроку.
  • С правой частью в кавычках мы выполняем поиск подстроки, поэтому мы проверяем, существует ли содержимое $OPTARG — с добавленными пробелами в начале и конце — где-либо в полном расширенном списке, сгенерированном ${FS_OPTIONS[*]}.
  • ! инвертирует логический статус выхода остальной части выражения (изменение 0 на 1 или 1 на 0).

Какая польза от этого синтаксиса вообще?

  • Строка в кавычках в RHS действует как обычный незакрепленный поиск подстроки. То есть [[ $foo = "bar" ]] истинно, только если переменная foo расширяется точно до bar, но [[ $foo =~ "bar" ]] истинно, если переменная foo расширяется и содержит bar в любом месте своего содержимого. Это полезная семантика сама по себе.

  • Цитирование определяется посимвольно, а не для всей строки. В качестве примера того, как это можно использовать:

    regex_pre='([[:space:]]|^)'
    literal_string='** match this exactly **'
    regex_post='([[:space:]]|$)'
    
    [[ $foo =~ ${regex_pre}"${literal_string}"${regex_post} ]]
    #          |            |                 |
    #          |            |                 \-> unquoted: acts like a regex
    #          |            \-> quoted: acts like a literal string
    #          \-> unquoted: acts like a regex
    

    ...соответствует ** match this exactly ** только тогда, когда он находится в начале строки или непосредственно перед пробелом, а также либо в конце, либо сразу после пробела, без необходимости писать регулярное выражение для литеральной строки между ними и без необходимости делать трюк с пробелами, показанный в вопросе.

вау, большое спасибо за любезное объяснение. последнюю часть (regex_pre~ regex_post) я не могу сейчас, но я проверю это позже (просто потому, что здесь так поздно).

Chan Kim 11.12.2020 15:04
ckim@chan-ubuntu:~/testbash$ test3.sh -f ubuntu
ok!
ckim@chan-ubuntu:~/testbash$ test3.sh -f ubunt.
Unsupported filesystem ubunt.
Use ubuntu/busybox

В руководстве bash сказано (в обсуждении [[...]]):

Любая часть шаблона может быть заключена в кавычки, чтобы часть в кавычках соответствовала строке.

Итак, чтобы обрабатывать ввод как регулярное выражение, а также добавить литеральные пробелы на концах, заключите пробелы в кавычки, но оставьте переменную без кавычек:

[[ " ${FS_OPTIONS[*]} " =~ " "$OPTARG" "  ]]
# .........................^^^-------^^^

Демонстрация:

$ OPTARG=ubuntu
$ [[ " ${FS_OPTIONS[*]} " =~ " "$OPTARG" "  ]] && echo Y || echo N
Y

$ OPTARG=ubunt.
$ [[ " ${FS_OPTIONS[*]} " =~ " "$OPTARG" "  ]] && echo Y || echo N
Y

$ OPTARG=ubunt
$ [[ " ${FS_OPTIONS[*]} " =~ " "$OPTARG" "  ]] && echo Y || echo N
N

Другие вопросы по теме