$(<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
складається лише з перенаправлень, що дає неозначені результати . Це дозволяє дозволити особливу поведінку оболонки Корна.
У 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
призначення втрачається згодом).
В bash
, IFS= read -rd '' var < file
(також працює в zsh
) є більш ефективним способом зчитування вмісту текстового файлу в змінну. Це також має перевагу збереження останніх символів нового рядка. Дивіться також $mapfile[file]
в zsh
(у zsh/mapfile
модулі та лише для звичайних файлів), який також працює з бінарними файлами.
Зауважимо, що варіанти на основі pdksh ksh
мають кілька варіацій порівняно з ksh93. Цікаво, що в mksh
(одній із цих оболонок, отриманих пдкш), в
var=$(<<'EOF'
That's multi-line
test with *all* sorts of "special"
characters
EOF
)
оптимізовано тим, що вміст документа тут (без знаків, що відкладаються) розширюється без використання тимчасового файлу або труби, як це в іншому випадку стосується тут документів, що робить його ефективним синтаксисом багаторядкового цитування.
Для того, щоб бути портативними для всіх версій ksh
, zsh
і bash
, найкраще обмежитися тільки $(<file)
уникати коментарів і беручи до уваги , що зміни змінних зроблені в межах можуть або не можуть бути збережені.
bash
буде інтерпретувати це якcat filename
", ви маєте на увазі, що така поведінка специфічна для заміни команд? Тому що, якщо я біжу< filename
сама, баш це не виганяє. Він нічого не виведе і поверне мене до підказки.