it-swarm-ru.tech

$ VAR vs $ {VAR} и цитировать или не цитировать

Я могу написать

VAR=$VAR1
VAR=${VAR1}
VAR="$VAR1"
VAR="${VAR1}"

конечный результат для меня все кажется примерно одинаковым. Зачем мне писать одно или другое? какие-нибудь из них не портативные/POSIX?

150
xenoterracide

VAR=$VAR1 - это упрощенная версия VAR=${VAR1}. Второе может сделать то, что первое не может, например, сослаться на индекс массива (не переносимый) или удалить подстроку (переносимый POSIX). См. Раздел Подробнее о переменных Руководства по Bash для начинающих и Расширение параметров в спецификации POSIX.

Использование кавычек вокруг переменной, как в rm -- "$VAR1" или rm -- "${VAR}" хорошая идея. Это делает содержимое переменной атомарной единицей. Если значение переменной содержит пробелы (ну, символы в $IFS специальная переменная, по умолчанию пробелы) или символы-заглушки, и вы не заключаете их в кавычки, тогда каждое слово рассматривается для генерации имени файла (всплытия), расширение которого дает столько аргументов, что вы делаете.

$ find .
.
./*r*
./-rf
./another
./filename
./spaced filename
./another spaced filename
./another spaced filename/x
$ var='spaced filename'
# usually, 'spaced filename' would come from the output of some command and you weren't expecting it
$ rm $var
rm: cannot remove 'spaced': No such file or directory
# oops! I just ran 'rm spaced filename'
$ var='*r*'
$ rm $var
# expands to: 'rm' '-rf' '*r*' 'another spaced filename'

$ find .
.
./another
./spaced filename
./another spaced filename
$ var='another spaced filename'
$ rm -- "$var"
$ find .
.
./another
./spaced filename

О переносимости: в соответствии с POSIX.1-2008 раздел 2.6.2 фигурные скобки являются необязательными.

108
Shawn J. Goff

${VAR} а также $VAR в точности эквивалентны. Для простого расширения переменной единственная причина использовать ${VAR} - это когда синтаксический анализ захватывает слишком много символов в имя переменной, как в ${VAR1}_$VAR2 (который без скобок будет эквивалентен ${VAR1_}$VAR2). Самые украшенные расширения (${VAR:=default}, ${VAR#prefix},…) Требуют скобки.

В присваивании переменной разделение поля (то есть разбиение пробела в значении) и расширение пути (то есть глобализация) отключены, поэтому VAR=$VAR1 в точности эквивалентно VAR="$VAR1", во всех оболочках POSIX и во всех pre-POSIX sh, о которых я слышал. (POSIX ref: простые команды ). По той же причине, VAR=* надежно устанавливает VAR в буквальную строку *; конечно VAR=a b устанавливает VAR на a, поскольку b, во-первых, является отдельным Word. Вообще говоря, двойные кавычки не нужны, если синтаксис Shell предполагает одно слово, например в case … in (но не в шаблоне), но даже здесь вы должны быть осторожны: например, POSIX указывает, что цели перенаправления (>$filename) не требуют цитирования в скриптах, но некоторые оболочки, включая bash, требуют двойных кавычек даже в скриптах. См. Когда необходима двойная кавычка? для более тщательного анализа.

Вам нужны двойные кавычки в других случаях, в частности в export VAR="${VAR1}" (что можно эквивалентно записать export "VAR=${VAR1}") во многих оболочках (POSIX оставляет этот случай открытым). Сходство этого случая с простыми назначениями и рассеянный характер списка случаев, когда вам не нужны двойные кавычки, - вот почему я рекомендую просто использовать двойные кавычки, если вы не хотите разбивать и использовать глобальные символы.

65
Gilles 'SO- stop being evil'

Цитата

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

Расширение:

this='foo'
that='bar'
these="$this"
those='$that'

Вывод:

for item in "$this" "$that" "$these" "$those"; do echo "$item"; done
foo
bar
foo
$that

Возможно, стоит упомянуть, что вы должны использовать цитату везде, где это возможно, по нескольким причинам, среди которых лучшими являются то, что это считается наилучшей практикой, и для удобства чтения. Кроме того, потому что Bash иногда бывает причудливым и часто из-за кажущихся нелогичными или неразумными/неожиданными способами, а цитата меняет неявные ожидания на явные, что уменьшает эту поверхность ошибки (или потенциальную вероятность появления в ней).

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

Подмена

Теперь рассмотрим также, что конструкция "${somevar}" используется для операций замещения. Несколько вариантов использования, таких как замена и массивы.

Замена (зачистка):

thisfile='foobar.txt.bak'
foo="${thisfile%.*}"   # removes shortest part of value in $thisfile matching after '%' from righthand side
bar="${thisfile%%.*}"  # removes longest matching

for item in "$foo" "$bar"; do echo "$item"; done
foobar.txt
foobar

Замена (замена):

foobar='Simplest, least effective, least powerful'
# ${var/find/replace_with}
foo="${foobar/least/most}"   #single occurrence
bar="${foobar//least/most}"  #global occurrence (all)

for item in "$foobar" "$foo" "$bar"; do echo "$item"; done
Simplest, least effective, least powerful
Simplest, most effective, least powerful
Simplest, most effective, most powerful

Массивы:

mkdir temp
# create files foo.txt, bar.txt, foobar.txt in temp folder
touch temp/{foo,bar,foobar}.txt
# alpha is array of output from ls  
alpha=($(ls temp/*))

echo "$alpha"         #  temp/foo.txt
echo "${alpha}"       #  temp/foo.txt
echo "${alpha[@]}"    #  temp/bar.txt  temp/foobar.txt  temp/foo.txt
echo "${#alpha}"      #  12 # length of first element (implicit index [0])
echo "${#alpha[@]}"   #  3  # number of elements
echo "${alpha[1]}"    #  temp/foobar.txt # second element
echo "${#alpha[1])"   #  15 # length of second element

for item in "${alpha[@]}"; do echo "$item"; done
temp/bar.txt
temp/foobar.txt
temp/foo.txt

Все это едва царапает поверхность "${var}" подстановочная конструкция. Оптимальной ссылкой для сценариев Bash Shell является онлайновая ссылка libre, TLDP Проект документации Linux https://www.tldp.org/LDP/abs/html/parameter-substitution.html

9
SYANiDE
ls -la

lrwxrwxrwx.  1 root root      31 Nov 17 13:13 prodhostname
lrwxrwxrwx.  1 root root      33 Nov 17 13:13 testhostname
lrwxrwxrwx.  1 root root      32 Nov 17 13:13 justname

конец тогда:

env=$1
    if [ ! -f /dirname/${env}hostname ]

стоит упомянуть в качестве более четкого примера использования фигурных скобок

0
ninjabber