$(<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 не догонит его. Он ничего не выдаст и вернет меня обратно к приглашению.