Выходные данные
# ls
и
# echo $(ls)
одинаковы. Что именно означает знак $ и круглые скобки?
Кроме того, что происходит на техническом уровне, который приводит к тому, что вывод этих двух команд будет одинаковым?
() и $ () используются для запуска команд в подоболочке
Подробнее см. http://tldp.org/LDP/abs/html/subshells.html 112]
Использование $ перед именем переменной вызывает значение, присвоенное переменной. Echo без $ будет просто выводить имя переменной на экран (или стандартное отображение).
Это замена команды для bash.
Подстановка команды позволяет выводу команды заменить саму команду. Подстановка команд происходит, когда команда заключена следующим образом:
blockquote>$(command) or `command`
http://www.gnu.org/software/bash/manual/bashref.html#Command-Substitution
Подробнее:
http://tldp.org/LDP/abs/html/commandsub.html
http : //wiki.bash-hackers.org/syntax/expansion/cmdsubst
И хороший пример, похожий на ваш вопрос:
http://bashshell.net / Shell-скрипты / с помощью команды-замещение-в-Баш-оболочки-скрипта /
Когда оболочка встречает текст, заключенный в $(
)
, она:
$(
и закрывающее )
). Как объясняет ответ heartsmagic , это один из двух доступных синтаксисов для подстановки команд .
На самом деле несколько необычно, чтобы выходные данные ls
были точно совпадает с выводом echo $(ls)
:
ek@Io:~/tmp$ ls
bar foo
ek@Io:~/tmp$ echo $(ls)
bar foo
ls
обычно разделяет имена файлов двумя или более пробелами или символом новой строки. Это помогает нам легче различать их, особенно потому, что пробелы в именах файлов встречаются довольно часто (но несколько последовательных пробелов встречаются реже).
Когда я запустил echo $(ls)
, произошло следующее.
Подстановка команд заменена $(ls)
на:
bar
foo
Вы можете быть удивлены, услышав это, так как это, вероятно, не то, что вы видите при запуске ls
само собой! Это несоответствие в том, что выводит ls
, объясняется ниже, но на самом деле это не причина, по которой вы в конечном итоге получаете один пробел между этими двумя словами. То же самое произошло бы, если бы $(ls)
были заменены на bar foo
(с двумя пробелами).
После этого оболочка выполнила разбиение слов , обрабатывая bar
и foo
как отдельные аргументы для команды echo
, а не как один аргумент, содержащий пространства.
Когда echo
получает несколько аргументов (за исключением опций, таких как -n
, которые обрабатываются специально и не печатаются вообще), он выводит их все, с одним пробелом между последующие аргументы. echo
затем печатает новую строку (если не была передана опция -n
).
Таким образом, echo $(ls)
показывает вывод, подобный bar foo
вместо bar foo
.
Если вы запустите ls
и в нем не будет ни одного файла, или только один файл, вывод ls
будет часто совпадать с выводом echo $(ls)
. Даже в этом случае оно не всегда будет одинаковым, например, когда имя файла содержит пробелы, отличные от изолированных (одиночных) пробелов:
ek@Io:~/tmp2$ touch 'my file'
ek@Io:~/tmp2$ ls
my file
ek@Io:~/tmp2$ echo $(ls)
my file
Когда ls
печатает несколько файлов, его вывод вряд ли будет точно так же, как на выходе из $(ls)
. Аналогично:
echo a b
и echo $(echo a b)
дают одинаковый выход, , но echo 'a b'
и echo $(echo 'a b')
нет. Это важно знать о подстановке команд - подстановки команд без кавычек могут быть разбиты на слова .
Если вы хотите предотвратить разбиение слов, вы можете заключить свое выражение для подстановки команд в двойные кавычки ("
). Обычно этого достаточно, и, в частности, он будет работать с приведенными выше примерами на основе echo
, а также с примером ls
для каталога с одной записью, содержащей пробелы:
ek@Io:~/tmp2$ echo "$(ls)"
my file
Однако, как как отмечалось выше, вы можете быть удивлены, обнаружив, что то, что вы видите при запуске ls
, часто не то, что передается в echo
вместо "$(ls)"
:
ek@Io:~/tmp$ ls
bar foo
ek@Io:~/tmp$ echo "$(ls)"
bar
foo
Это потому, что ls
] проверяет, является ли стандартный вывод терминалом , чтобы решить, как форматировать его вывод , если форматирование вывода не указано явно.
ls
выводит в вертикально отсортированных столбцах, как ls -C
. ls
перечисляет каждую запись в отдельной строке, как ls -1
. В подстановке команд стандартный вывод не является терминалом, потому что вывод команды не отправляется непосредственно на терминал, чтобы вы могли видеть - вместо этого он захватывается оболочкой и используется как часть другого команда.
Чтобы получить форматирование нескольких столбцов при запуске ls
посредством подстановки команд, передайте ему флаг -C
:
ek@Io:~/tmp$ echo "$(ls -C)"
bar foo
(dir
иногда предлагается в качестве альтернативы ls -C
, и будет также работать для этого, хотя dir
ведет себя как ls -C -b
, а не просто ls -C
.)
Другая причина ls
может иногда вести себя иначе, чем echo "$(ls)"
, это то, что ls
может быть псевдонимом оболочки . Запустите alias ls
, чтобы проверить; в Ubuntu вы обычно получаете alias ls='ls --color=auto'
, что означает, что когда ls
появляется в качестве первого слова команды, которую вы выполняете в интерактивном режиме (и в некоторых, но не во всех других обстоятельствах), она заменяется на ls --color=auto
.
Например, когда я запускаю ls
, в нем перечислены каталоги, окрашенные в синий цвет, и исполняемые файлы, окрашенные в зеленый цвет (а также реализует много других правил окраски). --color=auto
заставляет ls
печатать цветной вывод, когда стандартный вывод является терминалом, а не иначе.
Чтобы получить цветной вывод при запуске ls
посредством подстановки команд, передайте ему опцию --color
или --color=always
. Если хотите, вы можете объединить это с -C
:
echo $(ls -C --color)
Обратите внимание, что хотя вы можете сделать ls
псевдонимом для ls --color
или ls --color=always
вместо ls --color=auto
и ls --color=always
] не волнует, является ли стандартный вывод терминалом ... этот псевдоним все равно не заставит ls
производить цветной вывод при вызове подстановкой команды. Это связано с тем, что псевдонимы оболочки (в оболочках в стиле Борна , например bash ) раскрываются только тогда, когда оболочка видит их как первое слово команды (и они не наследуются подоболочками) .