В чем разница между ${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}". Если бы кто-нибудь мог объяснить это, я был бы признателен.
в качестве дополнительного вопроса-кто-нибудь знает принятый способ ссылаться на эти инкапсуляции?
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" 2The @ символ взаимодействует с цитированием иначе, чем *. В частности:
$@" [e]xpands к позиционным параметрам, начиная с одного. Когда расширение происходит в двойных кавычках, каждый параметр увеличивается до отдельного слова."- в массиве " [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