Я использовал один из следующих
echo $(stuff)
echo `stuff`
(где stuff
, например, pwd
или date
или что-то более сложное).
Затем мне сказали, что этот синтаксис неправильный, плохая практика, не элегантный, чрезмерный, избыточный, чрезмерно сложный, программирование культа грузов, нубистский, наивный и т. Д.
Но команда делает работу, так что именно случилось с ним?
shell-script
sh
echo
Камиль Мачоровски
источник
источник
echo $(echo $(echo $(echo$(echo $(stuff)))))
также делает работу, и до сих пор вы , вероятно , не будете использовать его, не так ли? ;-)stuff
. : DОтветы:
ТЛ; др
Подошва
stuff
, скорее всего, будет работать для вас.Полный ответ
Что происходит
Когда вы бежите
foo $(stuff)
, вот что происходит:stuff
пробеги;$(stuff)
в вызовеfoo
;foo
запускается, его аргументы командной строки, очевидно, зависят от того, чтоstuff
возвращено.Этот
$(…)
механизм называется «подстановка команд». В вашем случае основной командой является то,echo
что в основном выводит свои аргументы командной строки в стандартный вывод. Поэтому все, чтоstuff
пытается распечатать на стандартный вывод, захватывается, передаетсяecho
и распечатывается на стандартный выводecho
.Если вы хотите, чтобы вывод команды выводился
stuff
на стандартный вывод, просто запустите подошвуstuff
.`…`
Синтаксис служит той же цели, что и$(…)
(под тем же названием: «подстановки команд»), есть несколько отличий , хотя, так что вы не можете слепо поменять их. Смотрите этот FAQ и этот вопрос .Должен ли я избегать
echo $(stuff)
несмотря ни на что?Есть причина, по которой вы можете захотеть воспользоваться,
echo $(stuff)
если знаете, что делаете. По той же причине вам следует избегать,echo $(stuff)
если вы действительно не знаете, что делаете.Дело в том,
stuff
иecho $(stuff)
не совсем эквивалентны. Последнее означает вызов оператора split + glob на выходеstuff
со значением по умолчанию$IFS
. Двойная кавычка подстановки команды предотвращает это. Одинарная кавычка подстановки команд больше не делает подстановку команд.Чтобы наблюдать это, когда дело доходит до разделения, запустите эти команды:
И для суеты:
Как видите
echo "$(stuff)"
, эквивалентно (-ish *)stuff
. Вы могли бы использовать это, но какой смысл усложнять вещи таким образом?С другой стороны, если вы хотите, чтобы выходные данные
stuff
подвергались расщеплению + смещению, вы можете найти этоecho $(stuff)
полезным. Это должно быть ваше сознательное решение, хотя.Существуют команды, генерирующие выходные данные, которые должны быть оценены (включая расщепление, подстановку и т. Д.) И запущены оболочкой, так
eval "$(stuff)"
что это возможно (см. Этот ответ ). Я никогда не видел команду, которая нуждается в выводе, чтобы подвергнуться дополнительному расщеплению + смещению перед печатью . Умышленное использованиеecho $(stuff)
кажется очень необычным.Как насчет
var=$(stuff); echo "$var"
?Хорошая точка зрения. Этот фрагмент:
должен быть эквивалентен
echo "$(stuff)"
(-ish *) дляstuff
. Если это весь код, просто запуститеstuff
вместо этого.Однако, если вам нужно использовать вывод
stuff
более одного раза, тогда этот подходобычно лучше чем
Даже если
foo
естьecho
и вы попалиecho "$var"
в свой код, может быть, лучше оставить его таким. Что нужно учитывать:var=$(stuff)
stuff
пробежками один раз; даже если команда быстрая, избегать вычисления одного и того же результата дважды - это правильно. Или можетstuff
иметь другие эффекты, кроме записи в стандартный вывод (например, создание временного файла, запуск службы, запуск виртуальной машины, уведомление удаленного сервера), поэтому вы не хотите запускать его несколько раз.stuff
генерирует зависящий от времени или несколько случайный вывод, вы можете получить противоречивые результаты отfoo "$(stuff)"
иbar "$(stuff)"
. Послеvar=$(stuff)
того, как значение$var
зафиксировано, вы можете быть увереныfoo "$var"
иbar "$var"
получите идентичный аргумент командной строки.В некоторых случаях вместо
foo "$var"
вас может потребоваться (необходимость) использоватьfoo $var
, особенно еслиstuff
генерирует несколько аргументов дляfoo
(переменная массива может быть лучше, если ваша оболочка поддерживает это). Опять же, знайте, что вы делаете. Когда дело доходит доecho
разницы междуecho $var
иecho "$var"
такой же, как междуecho $(stuff)
иecho "$(stuff)"
.* Эквивалент ( -иш )?
Я сказал
echo "$(stuff)"
, эквивалентно (-ish) дляstuff
. Есть как минимум две проблемы, которые делают его не совсем эквивалентным:$(stuff)
работаетstuff
в подоболочке, так что лучше сказатьecho "$(stuff)"
, эквивалентно (-ish) для(stuff)
. Команды, которые влияют на оболочку, в которой они выполняются, если они находятся в подоболочке, не влияют на основную оболочку.В этом примере
stuff
этоa=1; echo "$a"
:Сравните это с
и с
Другой пример, начните с
stuff
того, чтоcd /; pwd
:и тест
stuff
и(stuff)
версии.echo
не очень хороший инструмент для отображения неконтролируемых данных . Этоecho "$var"
мы говорили о том, должно было бытьprintf '%s\n' "$var"
. Но поскольку в вопросе упоминаетсяecho
и поскольку наиболее вероятным решением является не использованиеecho
в первую очередь, я решил не вводитьprintf
до сих пор.stuff
или(stuff)
будет чередовать выходные данные stdout и stderr, в то время какecho $(stuff)
будет выводиться весь вывод stderr изstuff
(который запускается первым), и только затем вывод вывода stdout, обработанныйecho
(который запускается последним).$(…)
удаляет любой завершающий символ новой строки, а затемecho
добавляет его обратно. Так чтоecho "$(printf %s 'a')" | xxd
дает другой результат, чемprintf %s 'a' | xxd
.Некоторые команды (
ls
например) работают по-разному в зависимости от того, является ли стандартный вывод консолью или нет; такls | cat
не то же самоеls
делает. Аналогичноecho $(ls)
будет работать иначе, чемls
.Если
ls
оставить в стороне, в общем случае, если вы вынуждены использовать это другое поведение, тоstuff | cat
лучшеecho $(ls)
илиecho "$(ls)"
потому, что оно не вызывает все другие проблемы, упомянутые здесь.Возможно другой статус выхода (упомянуто для полноты этого вики-ответа; подробности см. В другом ответе, который заслуживает доверия).
источник
stuff
способ будет чередоватьstdout
иstderr
выводить, в то время какecho `stuff`
будут печататься всеstderr
выходные данныеstuff
, и только затемstdout
выходные данные.echo $(stuff)
может доставить вам гораздо больше неприятностей, какecho "$(stuff)"
если бы вы не хотели явно использовать глобализации и расширения.$(…)
удаляет любой завершающий символ новой строки, а затемecho
добавляет его обратно. Так чтоecho "$(printf %s 'a')" | xxd
дает другой результат, чемprintf %s 'a' | xxd
.ls
например) работают по-разному в зависимости от того, является ли стандартный вывод консолью или нет; такls | cat
не то же самоеls
делает. И, конечно,echo $(ls)
будет работать иначе, чемls
.Еще одно отличие: код завершения вложенной оболочки теряется, поэтому
echo
вместо него возвращается код выхода .источник
$?
будет кодом возвратаecho
(дляecho $(stuff)
) вместо того, которыйreturn
редактировалstuff
.stuff
Функцияreturn 1
(код выхода), ноecho
устанавливает его в «0» независимо от возврата кодаstuff
. Все еще должно быть в ответе.