Коли нам потрібні фігурні дужки навколо змінних оболонок?


657

Коли в сценаріях оболонок ми використовуємо {}при розширенні змінних?

Наприклад, я бачив таке:

var=10        # Declare variable

echo "${var}" # One use of the variable
echo "$var"   # Another use of the variable

Чи є суттєва різниця, чи це просто стиль? Чи один віддає перевагу іншому?

Відповіді:


750

У цьому конкретному прикладі це не має значення. Однак, {}in ${}корисні, якщо ви хочете розширити змінну fooв рядку

"${foo}bar"

оскільки "$foobar"замість цього буде розширюватися змінна, ідентифікована foobar.

Фігурні брекети також беззастережно потрібні, коли:

  • розширення елементів масиву, як у ${array[42]}
  • використання операцій розширення параметрів, як у ${filename%.*}(видалити розширення)
  • розширення позиційних параметрів понад 9: "$8 $9 ${10} ${11}"

Робити це скрізь, а не лише в потенційно неоднозначних випадках, можна вважати хорошою практикою програмування. Це як для послідовності, так і для уникнення сюрпризів, наприклад $foo_$bar.jpg, коли очевидно, що підкреслення стає частиною назви змінної, не очевидно.


106
{}відомий як розширення дужок . ${}відомий як змінне розширення. Вони роблять різні речі. Я б схвалив вас за винятком біта розширення.
Спенсер Ратбун

5
@NewUser " Отже, крім масивів, це насправді не потрібно ". Не так, дужки необхідні для розширення PARAMETER , дуже корисної конструкції в сценаріях. Я бачив багато сценаріїв sed і awk, які можна замінити трохи розширенням параметрів.
SiegeX

10
@caffinatedmonkey $()використовується для виконання команди, такої, яка md5sum=$(md5sum foo.bin)буде зберігати результат md5sum foo.binу змінній md5sum, тепер доступній для використання ${md5sum}. Крім того, +1 та багато іншого по духу для ОП за те, що вони зазначили, що це добра практика бути явною!
L0j1k

11
@ L0j1k Говорячи про чіткість, я вважаю важливим згадати, що він $()виконує свою команду з підшару .
Адріан Гюнтер

2
@karatedog ${1:-20}- це форма розширення параметрів. Тут це не очевидно, оскільки він в основному використовує цифри та арифметичні оператори, які обманюють нас, думаючи, що в цьому є арифметика, але він фактично посилається на позиційний параметр $1, який, якщо не визначено, буде замінено значенням за замовчуванням 20(синтаксис є ${variable:-default_value}).
Аарон

126

Змінні декларуються та призначаються без $і без {}. Ви повинні використовувати

var=10

призначити. Для того, щоб читати зі змінної (іншими словами, 'розширити' змінну), ви повинні використовувати $.

$var      # use the variable
${var}    # same as above
${var}bar # expand var, and append "bar" too
$varbar   # same as ${varbar}, i.e expand a variable called varbar, if it exists.

Це іноді мене бентежить - в інших мовах ми посилаємось на змінну так само, незалежно від того, що вона знаходиться зліва чи справа від призначення. Але сценарій оболонок відрізняється, $var=10не робить те, що ви можете подумати, що це робить!


34

Ви використовуєте {}для групування. Дужки потрібні для відстеження елементів масиву. Приклад:

dir=(*)           # store the contents of the directory into an array
echo "${dir[0]}"  # get the first entry.
echo "$dir[0]"    # incorrect

Я не міг зрозуміти перший рядок dir=(*). Наскільки мені відомо, dirце вбудована команда для переліку вмісту каталогів (еквівалентна ls -C -b). Не могли б ви пояснити?
Джарвіс

1
У програмуванні оболонок команди та аргументи повинні бути відокремлені один від одного пробілом. Тут ви бачите знак рівності без пробілів, тобто це змінне призначення. dir- це ім'я змінної, і круглі дужки використовуються для збору розширення імені файлу *в масив.
glenn jackman

27

Ви також можете виконати кілька текстових маніпуляцій всередині дужок:

STRING="./folder/subfolder/file.txt"
echo ${STRING} ${STRING%/*/*}

Результат:

./folder/subfolder/file.txt ./folder

або

STRING="This is a string"
echo ${STRING// /_}

Результат:

This_is_a_string

Ви праві в "звичайних змінних" не потрібні ... Але це корисніше для налагодження і для читання сценарію.


11

Кінець імені змінної зазвичай позначається пробілом або новим рядком. Але що робити, якщо після друку змінної величини ми не хочемо пробілу чи нової лінії? Фігурні дужки повідомляють інтерпретатору оболонки, де знаходиться кінець назви змінної.

Класичний приклад 1) - змінна оболонки без останнього пробілу

TIME=10

# WRONG: no such variable called 'TIMEsecs'
echo "Time taken = $TIMEsecs"

# What we want is $TIME followed by "secs" with no whitespace between the two.
echo "Time taken = ${TIME}secs"

Приклад 2) Класовий шлях Java з переліченими банками

# WRONG - no such variable LATESTVERSION_src
CLASSPATH=hibernate-$LATESTVERSION_src.zip:hibernate_$LATEST_VERSION.jar

# RIGHT
CLASSPATH=hibernate-${LATESTVERSION}_src.zip:hibernate_$LATEST_VERSION.jar

(У відповіді Фреда це вже зазначено, але його приклад трохи надто абстрактний)


5

Фігурні дужки завжди потрібні для доступу до елементів масиву та проведення розширення дужок.

Добре бути не надто обережним і використовувати {} для розширення змінної оболонки навіть тоді, коли немає можливості для двозначності.

Наприклад:

dir=log
prog=foo
path=/var/${dir}/${prog}      # excessive use of {}, not needed since / can't be a part of a shell variable name
logfile=${path}/${prog}.log   # same as above, . can't be a part of a shell variable name
path_copy=${path}             # {} is totally unnecessary
archive=${logfile}_arch       # {} is needed since _ can be a part of shell variable name

Отже, три рядки краще написати так:

path=/var/$dir/$prog
logfile=$path/$prog.log
path_copy=$path

що, безумовно, читабельніше.

Оскільки назва змінної не може починатися з цифри, оболонці не потрібно {}навколо нумерованих змінних (наприклад $1, $2тощо), якщо таке розширення не супроводжується цифрою. Це занадто тонко, і це робить явно використовувати {}в таких контекстах:

set app      # set $1 to app
fruit=$1le   # sets fruit to apple, but confusing
fruit=${1}le # sets fruit to apple, makes the intention clear

Подивитися:


1
It's good to be not over-cautious: Цікаво, що думає більшість людей. Постійно використовуйте фігурні брекети, щоб не забувати їх, коли вони потрібні, або використовувати їх лише там, де потрібно, для поліпшення читабельності.
Роджер Даль

1
Я думаю, що саме недостатня обізнаність призводить до того, що програмісти використовують фігурні фігури навіть тоді, коли вони не потрібні. Це незнання схоже на іншу поширену помилку - не використовувати подвійні лапки, щоб запобігти ненавмисному розщепленню слова чи поглибленню. В основі цього реальність полягає в тому, що програмісти не так серйозно ставляться до сценаріїв оболонок, як інші мови сценаріїв, такі як Python та Ruby.
codeforester

1
Правда, що. Мій домашній улюбленець - це те, що, здається, всі вважають, що всі змінні повинні бути усіма обмеженнями у скриптах оболонки :)
Роджер Дал

2

Після пропозицій SierraX та Петра щодо маніпулювання текстом, фігурні дужки {}використовуються для передачі змінної команді, наприклад:

Скажімо, у вас є файл sposi.txt, що містить перший рядок відомого італійського роману:

> sposi="somewhere/myfolder/sposi.txt"
> cat $sposi

Вихід: quel ramo del lago di como che volge a mezzogiorno

Тепер створіть дві змінні:

# Search the 2nd word found in the file that "sposi" variable points to
> word=$(cat $sposi | cut -d " " -f 2)

# This variable will replace the word
> new_word="filone"

Тепер замініть зміст змінного слова на нове слово , яке знаходиться у файлі sposi.txt

> sed -i "s/${word}/${new_word}/g" $sposi
> cat $sposi

Вихід: quel filone del lago di como che volge a mezzogiorno

Слово "рамо" замінено.


1
Це працює так само без фігурних дужок навколо змінних.
Армалі

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