Что означает `${1#*=}` в Bash?

Я нашел отличный ответ на StackOverflow, в котором объясняется, как передать ассоциативный массив в функцию. Может ли кто-нибудь помочь мне выяснить, что указывает синтаксис ${1#*=} в приведенном ниже коде? (Позаимствовано из этого ответа от Джейпал Сингх):

#!/bin/bash

declare -A weapons=(
  ['Straight Sword']=75
  ['Tainted Dagger']=54
  ['Imperial Sword']=90
  ['Edged Shuriken']=25
)

function print_array {
    eval "declare -A arg_array="${1#*=}
    for i in "${!arg_array[@]}"; do
       printf "%s\t%s\n" "$i ==> ${arg_array[$i]}"
    done
}

print_array "$(declare -p weapons)"

Вот мои догадки на данный момент (поправьте меня, если я ошибаюсь в каком-либо из них):
- 1 означает первый параметр, переданный функции ($1 или ${1})
- # означает индекс $1, который, поскольку $1 является ассоциативным массивом, # становится ключами $1
- * означает значения # ключей в ассоциированном массиве $1

Это оставляет =. Что это значит? Это похоже на способ показать, что вы хотите, чтобы # и * означали ключи и значения ассоциированного массива?


person GreenRaccoon23    schedule 09.07.2015    source источник
comment
Для справки отметим, что это решение небезопасно и допускает выполнение произвольного кода функцией из строки аргумента.   -  person Etan Reisner    schedule 09.07.2015


Ответы (2)


Фрагмент ${1#*=} не имеет ничего общего с ассоциативными массивами. (Синтаксис Bash очень согласован и совсем не сбивает с толку)*

Это соответствие шаблону значения первого аргумента (${1}) вашей функции или скрипта. Его синтаксис

${variable#glob}

куда

  • variable - любая переменная bash
  • glob — это любой шаблон глобуса (с учетом расширения имени пути) для сопоставления)

Он удаляет самое короткое совпадение, начиная с начала строки. Также есть ##, который удаляет самое длинное совпадение, начиная с начала переменной, %, который удаляет самое короткое совпадение, начиная с конца, и %%, который удаляет самое длинное совпадение, начиная с конца.


Так, например, следующий код:

myVar="abc=llamas&disclaimer=true"
echo "${myVar#*=}"

выведет llamas&disclaimer=true на экран.

С другой стороны,

myVar="abc=llamas&disclaimer=true"
echo ${myVar##*=}

напечатает true и

myVar="foobar is bad"
echo "${myVar%%b*}"

напечатает foo


* Это полностью объяснено в bash man страница; просто найдите строку ${parameter#word}, чтобы найти ее

person jpaugh    schedule 09.07.2015
comment
Это странно: отличный ответ, который совершенно неверен. # и % не захватывают указанный глобус, а удаляют его. ${myvar#*=} удалит abc= из значения примера и напечатает остальное. У меня это как один из тех, где намерение настолько ясно, что люди просто бездумно исправляют ошибки внутренне, даже не замечая, что они это делают. - person jthill; 20.11.2019
comment
@jthill Вы имеете в виду, что я поменял местами # и %? Честно говоря, я делаю это каждый раз, когда сижу за терминалом, чтобы использовать то или иное. Я отказался от попыток вспомнить это. Надеюсь, я не причинил слишком много вреда. - person jpaugh; 21.11.2019
comment
Нет, то, что я сказал: они не захватывают совпадающий контент, а удаляют его. echo ${myvar#*=} разделяет до первого = и печатает остальные. - person jthill; 21.11.2019
comment
@jthill Хорошо, теперь я понял. Спасибо! Вы правы, конечно; но я всегда использую их для захвата и, вероятно, буду продолжать думать о них как об операторах захвата. :-/ - person jpaugh; 21.11.2019

Он удаляет строку, совпадающую (самое короткое совпадение с начала) по шаблону *= в строке, оцениваемой $1.

$1 — это первый переданный позиционный параметр к оболочке.

Общий формат также может быть записан как ${var#patt}, где patt соответствует (самое короткое совпадение от начала) в $var и удаляется.

Пример:

var="first=middle=last"
echo "${var#*=}"

Выход:

middle=last

Если вместо # используется ##, то есть ${var##pat}, то pat соответствует самому длинному совпадению (от начала).

Пример:

var="first=middle=last"
echo "${var##*=}"

Выход:

last


Из руководства Bash:

${параметр#слово}

${параметр##слово}

Слово расширяется для создания шаблона так же, как и расширение имени файла (см. Расширение имени файла). Если шаблон соответствует началу расширенного значения параметра, то результатом расширения является расширенное значение параметра с кратчайшим совпадающим шаблоном (случай '#') или с самым длинным совпадающим шаблоном (случай '##') удален. Если параметр имеет значение «@» или «», операция удаления шаблона применяется к каждому позиционному параметру по очереди, а расширение представляет собой результирующий список. Если параметр представляет собой переменную массива с индексом «@» или «», операция удаления шаблона применяется к каждому элементу массива по очереди, а расширение представляет собой результирующий список.

person Jahid    schedule 09.07.2015
comment
Ссылка на раздел руководства: gnu.org/software/bash /ручной/ - person Etan Reisner; 09.07.2015
comment
Мне даже в голову не пришло расширение параметров! В этом есть смысл. Спасибо! - person GreenRaccoon23; 09.07.2015