В чем разница между эхо `date`, эхо“ `date`” и echo '`date`'?

23

В чем разница между этими тремя командами?

echo `date`
echo "`date`"
echo '`date`'

Я запутался в том, каковы различия на самом деле. Я думаю, что когда «вокруг», это означает, что это строка, поэтому эхо будет буквально выводить строку dateвместо отображения даты?

Джон
источник

Ответы:

19

`date` просто расширится до вывода dateкоманды. Однако он удаляет лишние пробелы в тех местах, где в выводе содержится более одного последовательного пробела. (Это связано с тем, что подстановка команд подвержена разбиению слов и из-за того, как echoкоманда обрабатывает несколько аргументов.)

В «date» двойные кавычки являются слабыми, поэтому они будут раскрывать переменные (попробуйте «$ PWD») и выполнять подстановку команд. Результат раскрытия передается команде как один аргумент echoс включенными последовательными пробелами: то есть разделение слов не выполняется.

В `` date` ' одинарные кавычки являются более сильными кавычками, поэтому они не допускают расширения переменных или подстановки команд внутри них.

Перейдите по этой ссылке для получения дополнительной информации.

Отредактировал первый пункт, как правильно указал Михаэль Зельманн в комментарии ниже .

Чираг Бхатия - чираг64
источник
1
Как именно называется `персонаж, который окружает дату? Если я правильно понимаю, метасимволы не будут работать в одинарных кавычках?
Джон
Если я правильно понимаю, метасимволы не будут работать в одинарных кавычках?
Джон
8
В этом сценарии `часто называют 'backtick' и различными документациями / книгами по Unix. На самом деле он не используется в качестве серьезного акцента Юникода, когда он сам по себе такой, хотя это название символа. И вы правы, что расширение метасимволов / выражений не произойдет, если вы заключите его в одинарные кавычки.
Джим Стюарт
Ваше первое утверждение неверно, поскольку вывод может немного отличаться в зависимости от даты или локали. Только вторая команда будет выводить то же самое, что и голая dateкоманда.
Jlliagre
1
@BonsiScott В HTML также удалено лишнее пространство между «Nov» и «1»;)
Izkata
16

И то и другое

echo `date`

а также

echo "`date`"

покажет дату. Выход из последнего выглядит как выход из запуска dateсам по себе.

Однако есть разница: тот, что заключен в "кавычки, "будет отправлен echoкак один аргумент. Кавычки инкапсулируют выходные данные всей команды как один аргумент. Так как echoпросто выводит свои аргументы по порядку, с пробелами между ними, он в основном будет выглядеть одинаково.

Вот пример тонкой разницы:

echo `date`

производит:

Fri Nov 1 01:48:45 EST 2013

но:

echo "`date`"

производит:

Fri Nov  1 01:48:49 EST 2013

Обратите внимание, что два пробела после Novбыли сокращены до одного без кавычек. Это связано с тем, что оболочка анализирует каждый разделенный пробелами элемент и отправляет результат в echo в качестве 6 аргументов. Когда вы цитируете его, echo получает один единственный аргумент, а кавычки сохраняют пробел.

Это становится намного важнее в командах, отличных от echo. Например, представьте команду, fooкоторая хочет два аргумента: дату и адрес электронной почты.

Это будет работать в этом сценарии:

foo "`date`" joeuser@example.com

Но это запутает скрипт, послав ему 7 аргументов:

foo `date` joeuser@example.com
Джим Стюарт
источник
3
Вы противоречивы в своем первом предложении. Первая и вторая формы не всегда выдают то же самое, что вы продемонстрируете позже.
июля
Спасибо. Я изменил формулировку, чтобы сделать ее более понятной.
Джим Стюарт
3

В оболочках POSIX, `date`это древняя форма подстановки команд. Современный синтаксис есть $(date).

В обоих случаях они расширяются до выходных данных dateс зачеркнутыми символами новой строки (при условии, что выходные данные не содержат NUL-символов).

Однако, если не в двойных кавычках и в контекстах списка (например, в аргументах простых команд, как echoв вашем случае), это расширение дополнительно зависит от:

  1. Разделение слов : это означает, что «вывод dateс разбитыми символами новой строки» разделяется в соответствии с текущим значением $IFSпеременной (по умолчанию содержит пробел, табуляцию и символ новой строки (и NUL с zsh)) на несколько слов .

    Например, если dateвыходы Fri 1 Nov 14:11:15 GMT 2013\n(как это часто бывает в английской местности и в материковой части британского часового пояса), и в $IFSнастоящее время содержит :, что будут разделить на 3 слово : Fri 1 Nov 14, 11и 15 GMT 2013.

  2. Генерация файла (ака подстановки ) ( за исключение zsh): то есть, каждое слово в результате расщепления выше ищется подстановочными символы ( *, ?, [...]хотя некоторые оболочки имеют более), а также расширен список имен файлов , которые соответствуют этим моделям. Например, если выход dateявляется ?%? 33 */*/* UVC 3432(как это часто бывает в венерианской локалей и UVC часовой пояс), и $IFSэто значение по умолчанию), то , что расширяется до всех не скрытым 3 символов имен файлов в текущем каталоге , чей средний символ %, 33, все не скрытые файлы во всех не скрытых подкаталогах всех не скрытых подкаталогов текущего каталога, UVCи 3432.

Поэтому:

  1. Вы должны всегда заключать в кавычки (с двойными кавычками) подстановки команд, если только вы не хотите, чтобы разделение слов или генерация имени файла выполнялись после его расширения.
  2. Если вы хотите разделить слова , установите $IFSсимволы, на которые вы хотите разделить слова.
  3. Если вам нужно разделение слов, но не генерация имени файла , вам нужно выполнить команду a, set +fчтобы отключить его.

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

Пример (использование -xупрощает просмотр происходящего):

$ bash --norc -x
bash-4.2$ IFS=:
+ IFS=:
bash-4.2$ echo `date`
++ date
+ echo 'Fri  1 Nov 14' 42 '33 GMT 2013'
Fri  1 Nov 14 42 33 GMT 2013
bash-4.2$ echo "`date`"
++ date
+ echo 'Fri  1 Nov 14:42:41 GMT 2013'
Fri  1 Nov 14:42:41 GMT 2013

bash-4.2$ cd /lib/modules
+ cd /lib/modules
bash-4.2$ export TZ=UVC LC_ALL=vs_VS
+ export TZ=UVC LC_ALL=vs_VS
+ TZ=UVC
+ LC_ALL=vs_VS
bash-4.2$ unset -v IFS     # get the default behaviour
+ unset -v IFS
bash-4.2$ echo `date`
++ date
+ echo '?%?' 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
?%? 33 3.10-2-amd64/build/arch 3.10-2-amd64/build/include 3.10-2-amd64/build/Makefile 3.10-2-amd64/build/Module.symvers 3.10-2-amd64/build/scripts 3.10-2-amd64/kernel/arch 3.10-2-amd64/kernel/crypto 3.10-2-amd64/kernel/drivers 3.10-2-amd64/kernel/fs 3.10-2-amd64/kernel/lib 3.10-2-amd64/kernel/mm 3.10-2-amd64/kernel/net 3.10-2-amd64/kernel/sound 3.10-2-amd64/source/arch 3.10-2-amd64/source/include 3.10-2-amd64/source/Makefile 3.10-2-amd64/source/scripts 3.10-2-amd64/updates/dkms 3.10-3-amd64/build/arch 3.10-3-amd64/build/include 3.10-3-amd64/build/Makefile 3.10-3-amd64/build/Module.symvers 3.10-3-amd64/build/scripts 3.10-3-amd64/kernel/arch 3.10-3-amd64/kernel/crypto 3.10-3-amd64/kernel/drivers 3.10-3-amd64/kernel/fs 3.10-3-amd64/kernel/lib 3.10-3-amd64/kernel/mm 3.10-3-amd64/kernel/net 3.10-3-amd64/kernel/sound 3.10-3-amd64/source/arch 3.10-3-amd64/source/include 3.10-3-amd64/source/Makefile 3.10-3-amd64/source/scripts 3.10-3-amd64/updates/dkms UVC 3432
bash-4.2$ echo "`date`"
++ date
+ echo '?%? 33 */*/* UVC 3432'
?%? 33 */*/* UVC 3432

Если выходные данные содержат символы NUL, то поведение меняется от оболочки к оболочке: некоторые удаляют их, некоторые усекают вывод при первом символе NUL, zshсохраняют их, но учтите, что в любом случае внешние команды не могут принимать аргументы, содержащие NUL

Стефан Шазелас
источник
Не существует такого понятия, как «оболочка POSIX». Существуют оболочки, которые могут соответствовать различным соответствующим стандартам POSIX, используя ограниченный набор их функций.
fpmurphy
0

С помощью `date` вы получите вывод даты, разделенной на несколько слов, потому что разделение слов выполняется после подстановки команд.

С помощью `` date` 'вы получите вывод даты в виде одного слова / параметра, так как между двойными кавычками есть подстановка команды, но вывод не анализируется дальше. То же самое верно с расширением переменной как "$ i" в моем примере ниже.

С помощью `` date` 'вы получаете буквальный `date`, поскольку между одинарными кавычками нет подстановки команд.

Возможно, различия в 3 формах будут более заметны таким образом:

> for i in `date`; do echo "$i"; done
Fr
1.
Nov
12:25:30
CET
2013

> for i in "`date`"; do echo "$i"; done
Fr 1. Nov 12:25:38 CET 2013

> for i in '`date`'; do echo "$i"; done
`date`
Майкл Зельманн
источник