ТЛ; др
Подошва stuff
, скорее всего, будет работать для вас.
Полный ответ
Что просходит
Когда вы бежите foo $(stuff)
, вот что происходит:
stuff
пробеги;- его вывод (stdout), вместо того, чтобы быть напечатанным, заменяет
$(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 "a b" echo $(echo "a b") echo "$(echo "a b")" # the shell is smart enough to identify the inner and outer quotes echo '$(echo "a b")'
И для суеты:
echo "/*" echo $(echo "/*") echo "$(echo "/*")" # the shell is smart enough to identify the inner and outer quotes echo '$(echo "/*")'
Как вы можете видеть echo "$(stuff)"
, эквивалентно (-ish *) stuff
. Вы могли бы использовать это, но какой смысл усложнять вещи таким образом?
С другой стороны, если вы хотите, чтобы выходные данные stuff
подвергались расщеплению + смещению, вы можете найти это echo $(stuff)
полезным. Это должно быть ваше сознательное решение, хотя.
Существуют команды, генерирующие выходные данные, которые должны быть оценены (включая расщепление, подстановку и т. Д.) И выполнены оболочкой, поэтому eval "$(stuff)"
такая возможность возможна (см. Этот ответ ). Я никогда не видел команду, которая нуждается в выводе, чтобы подвергнуться дополнительному расщеплению + смещению перед печатью . Намеренное использование echo $(stuff)
кажется очень необычным.
Как насчет var=$(stuff); echo "$var"
?
Хорошая точка зрения. Этот фрагмент:
var=$(stuff) echo "$var"
должен быть эквивалентен echo "$(stuff)"
(-ish *) для stuff
. Если это весь код, просто запустите stuff
.
Однако, если вам нужно использовать вывод stuff
более одного раза, тогда этот подход
var=$(stuff) foo "$var" bar "$var"
обычно лучше чем
foo "$(stuff)" bar "$(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"
:a=0 echo "$(a=1; echo "$a")" # echo "$(stuff)" echo "$a"
Сравните это с
a=0 a=1; echo "$a" # stuff echo "$a"
и с
a=0 (a=1; echo "$a") # (stuff) echo "$a"
Другой пример, начните с
stuff
того, чтоcd /; pwd
:cd /bin echo "$(cd /; pwd)" # echo "$(stuff)" 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)"
потому, что оно не вызывает все другие проблемы, упомянутые здесь.Возможно другой статус выхода (упомянуто для полноты этого вики-ответа; подробности см. В другом ответе, который заслуживает доверия).