В чем преимущество использования $ () вместо обратных кавычек в сценариях оболочки? - PullRequest
141 голосов
/ 26 февраля 2012

Существует два способа получения выходных данных командной строки в bash:

  1. Устаревшие обратные знаки оболочки Bourne ``:

     var=`command`
    
  2. $() синтаксис (который, насколько я знаю, специфичен для Bash, или, по крайней мере, не поддерживается старыми оболочками, отличными от POSIX, такими как оригинальный Bourne)

     var=$(command)
    

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

Ответы [ 8 ]

134 голосов
/ 26 февраля 2012

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

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

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) Теперь, когда конкретная команда может фактически не работать, я не проверял функциональность. Так что, если вы проголосуете за меня, вы потеряли из виду намерение :-) Это просто иллюстрация для того, как вы можете вкладывать, а не как готовый к выпуску фрагмент без ошибок.

48 голосов
/ 26 февраля 2012

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

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

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

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

25 голосов
/ 23 октября 2015

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

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

    $ 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`
    

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

    , которыйне является переносимым, так как оболочкам Борна и Корна потребуются эти обратные слэши, в то время как Bash и dash этого не делают.

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

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

    чем:

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

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

    Несколько других примеров:

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

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

    Например, эти действительные встроенные сценарии не работают в левом столбце, но работают в правом 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 ')'
    `                              )
    

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

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

См. также:

21 голосов
/ 26 февраля 2012

От человека Баш:

          $(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.
9 голосов
/ 26 февраля 2012

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

$(...)

визуально лучше, чем

`...`

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

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

6 голосов
/ 26 февраля 2012

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

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

Я думаю, что обратные помехи не позволяют этого.

3 голосов
/ 04 декабря 2015

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

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

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

2 голосов
/ 26 февраля 2012

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

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

$(<i>command</i>)

или (версия в кавычках):

`<i>command</i>`

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

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

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

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

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

\`<i>command</i>\`

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

$( (<i>command</i>) )

...