Подтвердить что ты не робот

В чем преимущество использования $() вместо обратных ссылок в сценариях оболочки?

Есть два способа захвата вывода командной строки в bash:

  • Возвращенные обратные оболочки оболочки Bourne ``:

     var=`command`
    
  • $() синтаксис (который, насколько я знаю, имеет значение Bash)

     var=$(command)
    

Есть ли какая-либо польза от использования второго синтаксиса по сравнению с обратными окнами? Или два полностью эквивалентных 100%?

4b9b3361

Ответ 1

Важнейшая из них - это способность их встраивать, команды внутри команд, не теряя здравого смысла, пытаясь понять, будет ли какая-то форма побега работать на обратном пути.

Пример, хотя и несколько придуманный:

deps=$(find /dir -name $(ls -1tr 201112[0-9][0-9]*.txt | tail -1l) -print)

который предоставит вам список всех файлов в дереве каталогов /dir, которые имеют те же имена, что и самый ранний текстовый файл с декабря 2011 года (a).

Другим примером может быть получение имени (а не полного пути) родительского каталога:

pax> cd /home/pax/xyzzy/plugh
pax> parent=$(basename $(dirname $PWD))
pax> echo $parent
xyzzy

(a) Теперь, когда определенная команда не работает, я не тестировал ее. Итак, если вы проголосуете за меня, вы упустили из виду намерение:-) Это означало как иллюстрацию того, как вы можете вложить, а не как бесплатный фрагмент, готовый к выпуску.

Ответ 2

Предположим, вы хотите найти каталог lib, соответствующий тому, где установлен gcc. У вас есть выбор:

libdir=$(dirname $(dirname $(which gcc)))/lib

libdir=`dirname \`dirname \\\`which gcc\\\`\``/lib

Первое проще, чем второе - используйте первый.

Ответ 3

От человека bash:

          $(command)
   or
          `command`

   Bash performs the expansion by executing command and replacing the com-
   mand  substitution  with  the  standard output of the command, with any
   trailing newlines deleted.  Embedded newlines are not deleted, but they
   may  be  removed during word splitting.  The command substitution $(cat
   file) can be replaced by the equivalent but faster $(< file).

   When the old-style backquote form of substitution  is  used,  backslash
   retains  its  literal  meaning except when followed by $, `, or \.  The
   first backquote not preceded by a backslash terminates the command sub-
   stitution.   When using the $(command) form, all characters between the
   parentheses make up the command; none are treated specially.

Ответ 4

Backticks (`...`) - это устаревший синтаксис, требуемый только самой старой из не-POSIX-совместимых оболочек bourne, а $(...) - POSIX и более предпочтительный по нескольким причинам:

  • Обратные косые черты (\) внутри backticks обрабатываются неочевидным образом:

    $ echo "`echo \\a`" "$(echo \\a)"
    a \a
    $ echo "`echo \\\\a`" "$(echo \\\\a)"
    \a \\a
    # Note that this is true for *single quotes* too!
    $ foo=`echo '\\'`; bar=$(echo '\\'); echo "foo is $foo, bar is $bar" 
    foo is \, bar is \\
    
  • Вложенная цитата внутри $() намного удобнее:

    echo "x is $(sed ... <<<"$y")"
    

    вместо:

    echo "x is `sed ... <<<\"$y\"`"
    

    или написать что-то вроде:

    IPs_inna_string=`awk "/\`cat /etc/myname\`/"'{print $1}' /etc/hosts`
    

    потому что $() использует совершенно новый контекст для цитирования

    который не переносится, поскольку оболочки Bourne и Korn потребуют этих обратных косых черт, в то время как Bash и тире нет.

  • Синтаксис для замены вложенных команд проще:

    x=$(grep "$(dirname "$path")" file)
    

    чем:

    x=`grep "\`dirname \"$path\"\`" file`
    

    потому что $() применяет совершенно новый контекст для цитирования, поэтому каждая подстановка команд защищена и может обрабатываться сама по себе без особой заботы о цитировании и экранировании. При использовании backticks он становится более уродливым и уродливым после двух и более уровней.

    Несколько примеров:

    echo `echo `ls``      # INCORRECT
    echo `echo \`ls\``    # CORRECT
    echo $(echo $(ls))    # CORRECT
    
  • Решает проблему непоследовательного поведения при использовании backquotes:

    • echo '\$x' выходы \$x
    • echo `echo '\$x'` выходы $x
    • echo $(echo '\$x') выходы \$x
  • Синтаксис Backticks имеет исторические ограничения на содержимое встроенной команды и не может обрабатывать некоторые допустимые сценарии, содержащие backquotes, в то время как более новая форма $() может обрабатывать любые допустимые встроенные script.

    Например, в противном случае действительные встроенные скрипты не работают в левом столбце, но работают с правой IEEE

    echo `                         echo $(
    cat <<\eof                     cat <<\eof
    a here-doc with `              a here-doc with )
    eof                            eof
    `                              )
    
    
    echo `                         echo $(
    echo abc # a comment with `    echo abc # a comment with )
    `                              )
    
    
    echo `                         echo $(
    echo '`'                       echo ')'
    `                              )
    

Поэтому синтаксис для $ -prefixed замена команд должен быть предпочтительным методом, потому что он визуально чист с чистым синтаксисом (улучшает человеческий и машинная читаемость), он является составным и интуитивно понятным, его внутренний синтаксический разбор является отдельным, и он также более согласован (со всеми другими расширениями, которые анализируются из двойных кавычек), где обратные ссылки являются единственным исключением, а символ ` замаскированный при прилегании к ", что делает его еще более трудным для чтения, особенно с небольшими или необычными шрифтами.

Источник: Почему $(...) предпочтительнее `...` (backticks)? в BashFAQ

См. также:

Ответ 5

В дополнение к другим ответам,

$(...)

выделяется визуально лучше, чем

`...`

Backticks выглядят слишком похожими на апострофы; это зависит от используемого шрифта.

(И, как я только заметил, backticks намного сложнее вводить в встроенные образцы кода.)

Ответ 6

$() позволяет вложенность.

out=$(echo today is $(date))

Я думаю, что backticks не позволяет этого.

Ответ 7

Это стандарт POSIX, который определяет форму замены $(command). Большинство используемых сегодня оболочек совместимы с POSIX и поддерживают эту предпочтительную форму над архаичной опорой обратного хода. В разделе подстановки команд (2.6.3) документа языка оболочки описывается следующее:

Подстановка команд позволяет заменить команду команды вместо имени команды. Подстановка команды должна выполняться, когда команда заключена в следующем порядке:

$(command)

или (backquoted version):

`command`

Оболочка расширяет подстановку команд, выполняя команду в среде подсетей (см. среда выполнения оболочки) и заменяя подстановку команд (текст команды плюс включая "$()" или backquotes) со стандартным выходом команды, удаляя последовательности одного или нескольких символов <newline> на конец подстановки. Встроенные символы <newline> до конца выхода не удаляются; однако они могут рассматриваться как полевые разделители и устраняются при разделении поля, в зависимости от значение IFS и цитирование, которое действует. Если вывод содержит любые нулевые байты, поведение неуказано.

В стиле обратной подстановки команды <backslash>сохраняют его буквальное значение, за исключением случаев, когда следуют: '$', '`' или <backslash>. Поиск соответствующей обратной кавычки должен выполняться по первому некотируемому неэкранированному кадровому кадру; во время этого поиска, если неэкзацированный backquote встречается внутри комментария оболочки, here-document, встроенная подстановка команды $(command) формы или строки с кавычками, undefined. Однокасканный или строка с двумя кавычками, которая начинается, но не заканчивается, в пределах "`...`" последовательность производит undefined результаты.

С формой $(command) все символы, следующие за открытием скобки для сопоставления закрывающей круглой скобки составляют команда. Любая действительная оболочка script может использоваться для команды, кроме script, состоящий исключительно из перенаправления, который производит неуказанные Результаты.

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

Подстановка команд может быть вложенной. Чтобы указать вложенность в backckoted version, приложение должно предшествовать внутренним обратным запросам с символами <backslash>; например:

\`command\`

Синтаксис командного языка оболочки имеет двусмысленность для расширений, начинающихся с "$((", который может ввести арифметическое расширение или подстановку команд, которая начинается с подоболочки. Арифметическое расширение имеет приоритет; то есть оболочка сначала должна определить может ли он анализировать расширение как арифметическое расширение и должен анализировать разложение только как замену команды если он определяет, что он не может разобрать расширение как арифметическое расширение. Оболочке не нужно оценивать вложенные расширения при выполнении этого определения. Если он встречает конец ввода, но уже не определил что он не может разобрать расширение как арифметическое расширение, оболочка должна рассматривать расширение как неполное арифметическое расширение и сообщать о синтаксической ошибке. Соответствующая заявка должна обеспечивать разделение "$(" и "(" на два токена (т.е. разделять их с пробелом) в подстановке команд, которая начинается с подоболочки. Например, подстановка команды, содержащая одну подоболочку, может быть записана как:

$( (command) )

Ответ 8

Это старый вопрос, но я придумал совершенно верный пример $(...) over `...`.

Я использовал удаленный рабочий стол для окон, запускающих cygwin, и хотел выполнить итерацию по команде. К сожалению, персонаж обратного хода не мог войти, либо из-за удаленной рабочей станции, либо из самого cygwin.

Разумно предположить, что знак доллара и скобки будут легче вводить такие странные настройки.