різниця між $ {} і $ () у скрипті оболонки


28
$ echo $(date)
Thu Jul 2 16:33:11 SGT 2015
$ echo ${date}

$ name=foo
$ echo $(name)
ksh: name:  not found

$ echo ${name}
foo

Здається, що $ {змінна} те саме, що і $ змінної. а $ () - виконувати команду. Навіщо тоді використовувати $ {}?


Відповіді:


39

$(command)"заміщення команд". Як вам здається, ви розумієте, він запускає command, захоплює свій результат і вставляє його в командний рядок, що містить $(…); наприклад,

$ ls -ld $(date +%B).txt
-rwxr-xr-x  1 Noob Noob    867 Jul  2 11:09 July.txt

${parameter}"заміщення параметрів". Багато інформації можна знайти на сторінці чоловічої оболонки, bash (1) , під заголовком " Розширення параметрів ":

${parameter}
    Значення параметра замінено. Дужки потрібні, коли параметр є позиційним параметром з більш ніж однією цифрою або коли за параметром слідує символ, який не слід інтерпретувати як частину його імені.

Позиційні параметри див. У розділі " Позиційні параметри " нижче. За його найпоширенішим використанням, як показано в інших відповідях, parameterце назва змінної. ${…}Форма, як зазначено в кінці попереднього абзацу, дозволяє отримати значення змінної (тобто ) і слідувати за ним відразу ж з буквою, цифрою або підкресленням:$variable_name

$ тварина = кішка
$ ехо $ тварини
                                # Немає такої змінної, як "тварини".
$ echo $ {animal} s
коти
$ echo $ animal_food
                                # Немає такої змінної, як "animal_food".
$ echo $ {тварина} _продукти
cat_food

Ви також можете це зробити цитатами:

$ echo "$ тварина" s
коти

Або як вправу в параметрах ви можете використовувати другу змінну:

$ множина = s
$ ехо $ тварина $ множина
коти

Але це лише крок 1. Наступний абзац на сторінці чоловіка цікавий, хоча і трохи виразний:

Якщо першим символом параметра є знак оклику ( !), вводиться рівень змінної непрямості. Bash використовує значення змінної, утвореної з решти параметра, як ім'я змінної; Потім ця змінна розширюється, і це значення використовується в решті підстановки, а не в значенні самого параметра . Це відомо як непряме розширення .     (Винятки)    Знак оклику повинен негайно слідувати лівій дужці, щоб ввести непряму силу.

Я не впевнений, як я можу зробити це зрозумілішим, окрім прикладу:

$ тварина = кішка
$ ехо $ тварина
кіт
$ cat = таббі
$ echo $ cat
таббі
$ echo $ {! тварина}
tabby                            # Якщо $ тварина - «кішка» , то $ {! тварина} - це кішка , тобто «таббі»

Тож назвемо цей крок 1½. Є багато цікавого, що ви можете зробити як крок 2:

$ тварина = кішка
$ echo $ {# тварина}
3                                # Довжина рядка
$ echo $ {тварина / в / ой}
корова                              # Заміна

Ви не можете зробити жодне з цих речей без {}брекетів.

Позиційні параметри

Розглянемо цей штучний приклад:

$ cat myecho.sh
ехо $ 1 $ 2 $ 3 $ 4 $ 5 $ 6 $ 7 $ 8 $ 9 $ 10 $ 11 $ 12 $ 13 $ 14 $ 15
$ ./myecho.sh Гей придурив, Кіт і скрипка, Корова перескочила місяць.
Гей диддл дидл, Кіт і скрипка, Хей0 Гей1 Гей2 Хей3 Гей4 Гей5

тому що оболонка не розуміє $10, $11і т.д. трактує , $10як якщо б воно було ${1}0. Але це розуміє ${10}, ${11}і т.д., як згадується на сторінці man ("позиційний параметр з більш ніж однією цифрою").

Але насправді не пишіть такі сценарії; є кращі способи поводження з довгими списками аргументів.

Вищенаведене (разом із багатьма іншими формами конструкцій) обговорюється з більшою довжиною на сторінці чоловічої оболонки, bash (1) .${parameter…something_else}

Примітка до котирувань

Зауважте, що ви завжди повинні цитувати змінні оболонки, якщо у вас немає вагомих причин цього не робити, і ви впевнені, що знаєте, що робите. Навпаки, хоча брекети можуть бути важливими, вони не такі важливі, як цитати.

$ filename = "розплідник rhyme.txt"
$ ls -ld $ {ім'я файлу}
ls: не вдається отримати доступ до розплідників: немає такого файлу чи каталогу
ls: не вдається отримати доступ до rhyme.txt: такого файлу чи каталогу немає
$ ls -ld "$ ім'я файлу"
-rwxr-xr-x 1 Noob Noob 5309 2 липня 11:09 дитяча рифма.txt

Це також стосується позиційних параметрів (тобто аргументів командного рядка; наприклад, "$1"), а також підстановки команд:

$ ls -ld $ (дата "+% B% Y"). txt
ls: не може отримати доступ до липня: такого файлу чи каталогу немає
ls: не вдається отримати доступ до 2015.txt: такого файлу чи каталогу немає
$ ls -ld "$ (дата" +% B% Y "). txt"
-rwxr-xr-x 1 Noob Noob 687 2 липня 11:09 липня 2015.txt

Дивіться котирування Баша, які не передбачені заміною команд, для короткого трактату про взаємодію між цитатами та $().


дякую за чудовий приклад. Чи можете ви детальніше використовувати! у вашому прикладі. Я не дуже розумію, як це працює.
Noob

@Noob: Добре, я детально розробив питання про використання !.
G-Man каже: "Відновіть Моніку"

Спасибі. Якось! Тварина насправді має на увазі змінну кішку замість кота значення. Чи можете ви також дозволити мені знати, як / в / з стає "c" в ехо $ {тварина / в / ow} Пояснення чоловіка баш якимось чином ... я не знаю. важко зрозуміти.
Noob

також, чи можете ви розробити цю фразу - "$ {parameter} Значення параметра замінено." заміщені чим? якщо параметр фрукт і його значення яблуко - фрукт = яблуко, то $ {фрукт} - яблуко заміщене ?? насправді не підміняйте значення, яке замінено тут
Noob

@Noob: " ${!animal}насправді йдеться про змінну $catзамість значення cat". Так, саме в цьому справа. "Як / у перетворюється на" с "в ехо $ {тварина / при / сові}?" / at не стає "c"; "Кішка" стає "коровою", коли "при" замінюється на "сов".
G-Man каже: "Відновіть Моніку"

7

У вашому прикладі $ var і $ {var} однакові. Однак фігурні дужки корисні, коли ви хочете розширити змінну в рядку:

    $ string=foo
    $ echo ${string}bar
      foobar
    $ echo $stringbar

    $ 

Таким чином, фігурні дужки забезпечують заміну змінної, щоб отримати ім'я нової змінної, яка сама підлягає заміні.


4

Зазвичай я це бачу частіше у струнах. Щось подібне не вийде:

var="a"
echo "$varRAW_STRING"

Але це буде:

var="a"
echo "${var}RAW_STRING"

Як ви правильно сказали, $()використовується для виконання команди:

dir_contents=$(ls)

Ви також можете використовувати задні підставки, але я вважаю $()більш універсальними. З одного боку, backticks не може бути (легко) вкладеним.

date_directory=`ls `date '+%Y-%m-%d'`` # Makes no sense
date_directory=$(ls $(date '+%Y-%m-%d')) # Much better

На насправді, зворотні лапки можуть бути вкладеними: date_directory=`ls \`date '+%Y-%m-%d'\``. Але це жахливо потворно; $(…)набагато чіткіше і простіше у використанні.
G-Man каже: «Відновіть Моніку»

Гаразд, досить справедливо. Це технічно можливо, але я не можу собі уявити, щоб хто-небудь робив це тільки з-за читабельності
розмірковував

1
Ну, `…`був (тільки) синтаксис для підстановки команд в протягом багатьох років , перш ніж був винайдений, так що вам не потрібно уявити нічого - люди зробили це. $(…)
G-Man каже: "Відновіть Моніку"

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