В чем разница между ${var}, "$var" и "${var}" в оболочке Bash?



что говорит название: Что значит инкапсулировать переменную в {},"" или "{}"? Я не смог найти никаких объяснений в интернете по этому поводу-я не мог ссылаться на них, за исключением использования символов, которые ничего не дают.



вот пример:



declare -a groups

groups+=("CN=exampleexample,OU=exampleexample,OU=exampleexample,DC=example,DC=com")
groups+=("CN=example example,OU=example example,OU=example example,DC=example,DC=com")


это:



for group in "${groups[@]}"; do
echo $group
done


оказывается, сильно отличается от этого:



for group in $groups; do
echo $group
done


и так:



for group in ${groups}; do
echo $group
done


только сначала один выполняет то, что я хочу: перебирать каждый элемент в массиве. Я не совсем понимаю разницу между $groups,"$groups",${groups} и "${groups}". Если бы кто-нибудь мог объяснить это, я был бы признателен.



в качестве дополнительного вопроса-кто-нибудь знает принятый способ ссылаться на эти инкапсуляции?

1180   6  

6 ответов:

фигурные скобки ($var и ${var})

в большинстве случаев, $var и ${var} то же самое:

var=foo
echo $var
# foo
echo ${var}
# foo

фигурные скобки нужны только для разрешения неоднозначности в выражениях:

var=foo
echo $varbar
# Prints nothing because there is no variable 'varbar'
echo ${var}bar
# foobar

кавычки ($var и "$var" и "${var}")

когда вы добавляете двойные кавычки вокруг переменной, вы говорите оболочке, чтобы она рассматривала ее как одно слово, даже если она содержит пробелы:

var="foo bar"
for i in "$var"; do # Expands to 'for i in "foo bar"; do...'
    echo $i         #   so only runs the loop once
done
# foo bar

сравните это поведение с следующее:

var="foo bar"
for i in $var; do # Expands to 'for i in foo bar; do...'
    echo $i       #   so runs the loop twice, once for each argument
done
# foo
# bar

С $var и ${var}, фигурные скобки нужны только для устранения неоднозначности, например:

var="foo bar"
for i in "$varbar"; do # Expands to 'for i in ""; do...' since there is no
    echo $i            #   variable named 'varbar', so loop runs once and
done                   #   prints nothing (actually "")

var="foo bar"
for i in "${var}bar"; do # Expands to 'for i in "foo barbar"; do...'
    echo $i              #   so runs the loop once
done
# foo barbar

обратите внимание, что "${var}bar" во втором примере выше также может быть написано "${var}"bar, в этом случае вам больше не нужны фигурные скобки, т. е. "$var"bar. Однако, если у вас есть много кавычек в вашей строке, эти альтернативные формы могут стать трудными для чтения (и, следовательно, трудно поддерживать). на этой странице обеспечивает хорошее введение в цитирование в Баш.

массивы ($var и $var[@] и ${var[@]})

теперь для вашего массива. Согласно bash manual:

ссылка на переменную массива без индекса эквивалентна ссылке на массив с индексом 0.

другими словами, если вы не укажете индекс [], вы получаете первый элемент массива:

foo=(a b c)
echo $foo
# a

который точно так же как

foo=(a b c)
echo ${foo}
# a

чтобы получить все элементы массива, нужно использовать @ как индекс, например ${foo[@]}. Фигурные скобки требуются с массивами, потому что без них оболочка будет расширять $foo часть первая, давая первый элемент массива, за которым следует литерал [@]:

foo=(a b c)
echo ${foo[@]}
# a b c
echo $foo[@]
# a[@]

на этой странице это хорошее введение в массивы в Bash.

котировки повторно (${foo[@]} и "${foo[@]}")

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

foo=("the first" "the second")
for i in "${foo[@]}"; do # Expands to 'for i in "the first" "the second"; do...'
    echo $i              #   so the loop runs twice
done
# the first
# the second

сравните это с поведением без двойных кавычек:

foo=("the first" "the second")
for i in ${foo[@]}; do # Expands to 'for i in the first the second; do...'
    echo $i            #   so the loop runs four times!
done
# the
# first
# the
# second

нужно различать массивы и простые переменные - и ваш пример с использованием массива.

для простых переменных:

  • $var и ${var} точно эквивалентны.
  • "$var" и "${var}" точно эквивалентны.

однако эти две пары не на 100% идентичны во всех случаях. Рассмотрим вывод ниже:

$ var="  abc  def  "
$ printf "X%sX\n" $var
XabcX
XdefX
$ printf "X%sX\n" "${var}"
X  abc  def  X
$

без двойных кавычек вокруг переменной, внутренняя интервал теряется, и расширение рассматривается как два аргумента для . С двойные кавычки вокруг переменной, внутренний интервал сохраняется и расширение рассматривается как один аргумент .

с массивами правила одинаковы и различны.

  • если groups - это массив, реферирование $groups или ${groups} равносильно ссылке ${groups[0]}, нулевой элемент матрица.
  • ссылка "${groups[@]}" аналогично ссылок "$@"; он сохраняет интервал между отдельными элементами массива и возвращает список значений, по одному значению на элемент массива.
  • ссылка ${groups[@]} без двойных кавычек не сохраняет интервал и может ввести больше значений, чем есть элементы в массиве, если некоторые из элементов содержат пробелы.

например:

$ groups=("abc def" "  pqr  xyz  ")
$ printf "X%sX\n" ${groups[@]}
XabcX
XdefX
XpqrX
XxyzX
$ printf "X%sX\n" "${groups[@]}"
Xabc defX
X  pqr  xyz  X
$ printf "X%sX\n" $groups
XabcX
XdefX
$ printf "X%sX\n" "$groups"
Xabc defX
$

используя * вместо @ приводит к тонко разные результаты.

см. также как перебирать аргументы в A bash скрипт.

TL; DR

все примеры, которые вы даете, являются вариациями на Bash Оболочки Расширения. Расширения происходят в определенном порядке, и некоторые из них имеют конкретные случаи использования.

фигурные скобки как разделители токенов

The ${var} синтаксис в основном используется для разграничения неоднозначных маркеров. Например, рассмотрим следующее:

$ var1=foo; var2=bar; var12=12
$ echo $var12
12
$ echo ${var1}2
foo2

фигурные скобки в расширениях массива

фигурные скобки необходимы для доступа к элементам массив и другие специальные разложения. Например:

$ foo=(1 2 3)

# Returns first element only.
$ echo $foo
1

# Returns all array elements.
$ echo ${foo[*]}
1 2 3

# Returns number of elements in array.
$ echo ${#foo[*]}
3

разметка

большинство остальных ваших вопросов связаны с цитированием и тем, как оболочка маркирует ввод. Рассмотрим разницу в том, как оболочка выполняет разбиение в следующих примерах:

$ var1=foo; var2=bar; count_params () { echo $#; }

# Variables are interpolated into a single string.
$ count_params "$var1 $var2"
1

# Each variable is quoted separately, created two arguments.
$ count_params "$var1" "$var2"
2

The @ символ взаимодействует с цитированием иначе, чем *. В частности:

  1. $@ " [e]xpands к позиционным параметрам, начиная с одного. Когда расширение происходит в двойных кавычках, каждый параметр увеличивается до отдельного слова."
  2. в массиве " [i] f слово в двойных кавычках, ${name[*]} расширяется до одного слова со значением каждого элемента массива, разделенного первым символом переменной IFS, и ${name[@]} расширяет каждый элемент имени до отдельного слова."

вы можете увидеть это в действии следующим образом:

$ count_params () { echo $#; }
$ set -- foo bar baz 

$ count_params "$@"
3

$ count_params "$*"
1

использование заключенного в кавычки расширения имеет большое значение, когда переменные ссылаются на значения с пробелами или специальными символами, которые могут помешать оболочке разбивать слова так, как вы намереваетесь. Смотрите цитирую подробнее о том, как цитирование работает в Bash.

второе предложение первого абзаца под Расширение Параметр на man bash говорит,

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

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

foo='bar'
echo "$foobar"
# nothing
echo "${foo}bar"
barbar

если Вы читаете дальше, вы обнаружите,

фигурные скобки требуются, когда параметр является позиционным параметром с более чем одной цифрой...

давайте:
$ set -- {0..100}
$ echo 
12
$ echo 
20

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

конечно, вам также нужны фигурные скобки, чтобы сделать мощные функции расширения параметров как

${parameter:-word}
${parameter:=word}
${parameter:?word}
… [read the section for more]

а также расширение массива.

связанный случай, не охваченный выше. Цитирование пустой переменной, похоже, меняет ситуацию для test -n. Это специально приведено в качестве примера в info текст coreutils, но не совсем объяснил:

16.3.4 String tests
-------------------

These options test string characteristics.  You may need to quote
STRING arguments for the shell.  For example:

     test -n "$V"

  The quotes here prevent the wrong arguments from being passed to
`test' if `$V' is empty or contains special characters.

Я хотел бы услышать детальное объяснение. Мое тестирование подтверждает это, и теперь я цитирую свои переменные для всех строковых тестов, чтобы избежать-z и -n возвращает тот же результат.

$ unset a
$ if [ -z $a ]; then echo unset; else echo set; fi
unset
$ if [ -n $a ]; then echo set; else echo unset; fi    
set                                                   # highly unexpected!

$ unset a
$ if [ -z "$a" ]; then echo unset; else echo set; fi
unset
$ if [ -n "$a" ]; then echo set; else echo unset; fi
unset                                                 # much better

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

${groups%example}

или синтаксис, как это, где вы хотите сделать что-то с переменной перед возвращением значения.

теперь, если вы видите свой код, вся магия находится внутри

${groups[@]}

магия, потому что вы не можете написать просто: $groups[@]

вы помещаете свою переменную внутрь {} потому что вы хотите использовать специальные символы [] и @. Вы не можете назвать или вызвать свою переменную просто:@ или something[] потому что это зарезервированные символы для других операций и имена.

Comments

    Ничего не найдено.