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

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

  1. Legacy Bourne shell backticks ``:

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

     var=$(command)
    

есть ли польза от использования второго синтаксиса по сравнению с backticks? Или два полностью 100% аналог?

8 ответов


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

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

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


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

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

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

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


от man 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.

обратные апострофы (`...`) является устаревшим синтаксисом, требуемым только самым старым из не-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 }' /etc/hosts`
    

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

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

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

    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, в то время как более новый $() форма может обрабатывать любой допустимый встроенный скрипт.

    например, эти в противном случае допустимые встроенные скрипты не работают в левом столбце, но работают на право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 ')'
    `                              )
    
синтаксис $-префикс команду должен быть предпочтительным методом, потому что он визуально ясен с чистым синтаксисом (улучшает читаемость человека и машины), он является вложенным и интуитивно понятным, его внутренний синтаксический анализ является отдельным, а также более последовательным (со всеми другими расширениями, которые анализируются изнутри двойных кавычек), где backticks являются единственными исключение и ` характер легко замаскирован, когда рядом с " что делает его еще более трудным для чтения, особенно с маленькими или необычным шрифтом.

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

Читайте также:


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

$(...)

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

`...`

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

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


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

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

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


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

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

$(command)

или (backquoted версия):

`command`

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

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

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

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

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

\`command\`

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

$( (command) )


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

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

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