$(<file)
(также работает с `<file`
) - специальный оператор оболочки Korn, скопированный с помощью zsh
и bash
. Это действительно похоже на подстановку команд, но это не совсем так.
В оболочках POSIX простая команда:
< file var1=value1 > file2 cmd 2> file3 args 3> file4
Все части являются необязательными, вы можете иметь только перенаправления, только команды, только назначения или комбинации.
Если есть перенаправления, но нет команды, перенаправления выполняются (то есть, > file
они открываются и усекаются file
), но тогда ничего не происходит. Так
< file
Открывается file
для чтения, но тогда ничего не происходит, так как нет команды. Так что file
тогда закрыто и все. Если бы $(< file)
была простая подстановка команд , то она бы расширилась до нуля.
В спецификации POSIX , в $(script)
, если script
состоит только из перенаправлений, что дает неопределенный результат . Это позволяет этому особому поведению оболочки Korn.
В ksh (здесь протестировано с ksh93u+
), если скрипт состоит из одной и только одной простой команды (хотя комментарии разрешены до и после), которая состоит только из перенаправлений (без команды, без назначения) и если первое перенаправление является stdin (fd 0) только перенаправление ввода <
, <<
или <<<
:
$(< file)
$(0< file)
$(<&3)
(также $(0>&3)
фактически, поскольку это - тот же самый оператор)
$(< file > foo 2> $(whatever))
но нет:
$(> foo < file)
- ни
$(0<> file)
- ни
$(< file; sleep 1)
- ни
$(< file; < file2)
затем
- все, кроме первого перенаправления игнорируются (они анализируются)
- и он расширяется до содержимого файла / heredoc / herestring (или чего угодно, что может быть прочитано из файлового дескриптора, если используются такие вещи
<&3
), минуя завершающие символы новой строки.
как будто используя, $(cat < file)
кроме этого
- чтение выполняется внутри оболочки, а не
cat
- ни труба, ни дополнительный процесс не вовлечены
- как следствие вышесказанного, поскольку код внутри не запускается в подоболочке, любые изменения остаются после него (как в
$(<${file=foo.txt})
или $(<file$((++n)))
)
- Ошибки чтения (но не ошибки при открытии файлов или дублировании файловых дескрипторов) игнорируются.
В zsh
это же самое , за исключением того , что особое поведение срабатывает только , когда есть только один вход Перенаправление файл ( <file
или 0< file
, нет <&3
, <<<here
, < a < b
...)
Тем не менее, за исключением случаев эмуляции других оболочек, в:
< file
<&3
<<< here...
то есть, когда есть только входные перенаправления без команд, вне подстановки команд zsh
запускается $READNULLCMD
(пейджер по умолчанию), а при наличии как входных, так и выходных перенаправлений $NULLCMD
( cat
по умолчанию), так что даже если $(<&3)
он не распознается как специальный оператор, он все равно будет работать как в ksh
, вызывая для этого пейджер (этот пейджер действует так, cat
как его stdout будет конвейером).
Однако в то время как ksh
«s $(< a < b)
будет расширяться на содержание a
, в zsh
, она расширяется к содержанию a
и b
(или только b
если multios
опция выключена), $(< a > b)
будет копировать a
в b
и расширять ничего, и т.д.
bash
имеет похожий оператор, но с некоторыми отличиями:
комментарии разрешены до, но не после:
echo "$(
# getting the content of file
< file)"
работает но:
echo "$(< file
# getting the content of file
)"
расширяется в ничто.
как в zsh
только один файл STDIN Перенаправление, хотя нет никакого падения назад к $READNULLCMD
, так $(<&3)
, $(< a < b)
действительно выполнять переадресацию , но расширить ничего.
- по какой-то причине, хотя
bash
и не вызывает cat
, он все еще разветвляется процесс, который передает содержимое файла через канал, что делает его гораздо меньше оптимизации, чем в других оболочках. По сути, это как $(cat < file)
где cat
бы был встроен cat
.
- как следствие вышеизложенного, любое изменение, внесенное в него, впоследствии теряется (например, в
$(<${file=foo.txt})
упомянутом выше случае это $file
назначение теряется впоследствии).
In bash
, IFS= read -rd '' var < file
(также работает в zsh
) - более эффективный способ чтения содержимого текстового файла в переменную. Это также имеет преимущество сохранения конечных символов новой строки. Смотрите также $mapfile[file]
в zsh
(в zsh/mapfile
модуле и только для обычных файлов), который также работает с двоичными файлами.
Обратите внимание, что варианты на основе pdksh ksh
имеют несколько вариаций по сравнению с ksh93. Интересно, что mksh
(одна из этих оболочек, полученных из pdksh), в
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
оптимизирован тем, что содержимое документа здесь (без завершающих символов) расширяется без использования временного файла или канала, как в случае с документами здесь, что делает его эффективным синтаксисом многострочного цитирования.
Быть переносимым на все версии ksh
, zsh
и bash
, лучше всего, ограничиваться только $(<file)
избеганием комментариев и помнить, что изменения переменных, сделанные внутри, могут сохраняться или не сохраняться.
bash
будет интерпретировать это какcat filename
», вы имеете в виду, что это поведение относится к подстановке команд? Потому что, если я запускаю< filename
сам, bash не догонит его. Он ничего не выдаст и вернет меня обратно к приглашению.