$ VAR проти $ {VAR} і цитувати чи не цитувати


Відповіді:


99

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

Щодо портативності: Згідно з розділом 2.6.2 POSIX.1-2008 , фігурні брекети необов’язкові.


@shawn оновив моє запитання, оскільки мені також цікаво портативність
xenoterracide

@shawn: я сумніваюся, що ваш приклад справедливий. Чи є у вас реальний приклад оболонки, де var1=$varрозширення дає помилку?
alex

@ Алекс: Дякую Я думав, що перевірив це в командному рядку, але зробив це неправильно. Я змінив приклад.
Шон Дж. Гофф

З оновленим прикладом краще пам’ятати, що ви, як правило, бажаєте цитованої версії, так як приклад - це дуже важливий випадок.
alex

9
@Shawn: цитати не потрібні у дорученні. Вони необхідні в більшості інших видів використання, в тому числі export VAR=$VAR1. Що стосується брекетів, вони є необов’язковими (перевірте четвертий абзац розділу, який ви цитували; це стосується всіх оболонок, що пред'являються до POSIX та POSIX).
Жиль

60

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

У присвоєнні змінної поділ поля (тобто розщеплення на пробіл у значенні) та розширення імені тракту (тобто глобалізація) вимикаються, тому VAR=$VAR1точно рівнозначні VAR="$VAR1"в усіх оболонках POSIX та в усіх попередніх POSIX sh, про які я чув . (POSIX ref: прості команди ). З цієї ж причини VAR=*надійно налаштовується VARна буквальний рядок *; звичайно VAR=a bвстановлює VARдля aоскільки bокреме слово в першу чергу. Взагалі подвійні лапки непотрібні, коли синтаксис оболонки очікує одне слово, наприклад уcase … in (але не в шаблоні), але навіть там потрібно бути обережним: наприклад, POSIX вказує, щоЦілі переспрямування ( >$filename) не вимагають цитування в скриптах, але для декількох оболонок, включаючи bash, потрібні подвійні лапки навіть у скриптах. Див. Коли потрібно подвійне цитування? для більш ретельного аналізу.

Вам потрібні подвійні лапки в інших випадках, зокрема у export VAR="${VAR1}"(що може бути рівнозначно написано export "VAR=${VAR1}") у багатьох оболонках (POSIX залишає цей випадок відкритим). Подібність цього випадку з простими завданнями та розсіяний характер списку випадків, коли вам не потрібні подвійні лапки, тому я рекомендую просто використовувати подвійні лапки, якщо ви не хочете розділити та поглибити.


2
Як правило, я завжди буду цитувати змінні розширення, навіть коли знаю, що значення не міститиме жодних IFSсимволів, тому що я хочу бути за звичкою. Єдиним винятком є ​​те, що я не цитую значення під час виконання змінної задачі (якщо не потрібно, наприклад, коли значення містить пробіл). Це робить виділення синтаксису редактора більш корисним, коли є підстановки команд, такі як FOO=$(BAR=$(BAZ=blah; printf %s "${BAZ}"); printf %s "${BAR}"). Замість того, щоб розфарбувати все «рядовим» кольором, я отримую виділення синтаксису вкладеного коду. Це також, чому я уникаю зворотних посилань.
Річард Хансен

У той час як >$fileв нормі в сценаріях POSIX, це не в Баш , навіть якщо неінтерактивний (якщо відповідність POSIX не відслідковуються з допомогою $POSIXLY_CORRECTабо --posix...).
Стефан Шазелас

Хоча це правда, що котирування не потрібні VAR=$VAR1, мене іноді дивують local VAR=$VAR1, які, як я пам'ятаю, працювали по-різному, принаймні в деяких оболонках. Але атм, я не можу відтворити розбіжність.
сумнівним

Гаразд, знайшов проблему, яку я запам’ятав . Він виявляється лише в деяких оболонках.
сумнівним

@dubiousjim local VAR=$VAR1це як export VAR=$VAR1, це залежить від оболонки.
Жиль

8

Цитата

Вважайте, що подвійне цитування використовується для змінного розширення, а одноцитата використовується для сильного котирування, тобто розширення sans.

Розширення:

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 є безкоштовна онлайн-посилання, TLDP, Документаційний проект Linuxhttps://www.tldp.org/LDP/abs/html/parameter-substitution.html


1
дуже інформативний.
orion elenzil

0
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 ]

Варто згадати як більш чіткий приклад використання фігур

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.