Так, оболонки, і bashзокрема, уважно читають файл по одному рядку, тому він працює так само, як коли ви його інтерактивно використовуєте.
Ви помітите, що коли файл не є вигідним (як труба), bashнавіть читає один байт за один раз, щоб бути впевненим, що він не читає минулого \nсимволу. Коли файл є шукаючим, він оптимізується, читаючи повні блоки за один раз, але звертайтеся до того, як після\n .
Це означає, що ви можете робити такі речі:
bash << \EOF
read var
var's content
echo "$var"
EOF
Або пишіть сценарії, які самі оновлюються. Що ви б не змогли зробити, якби це не дало вам гарантії.
Зараз рідко ви хочете робити такі речі, і, як ви з’ясували, ця функція, як правило, заважає частіше, ніж це корисно.
Щоб уникнути цього, ви можете спробувати переконатися, що ви не змінюєте файл на місці (наприклад, модифікуйте копію та перемістіть її на місце (наприклад, sed -iабоperl -pi й деякі редактори роблять, наприклад)).
Або ви можете написати свій сценарій так:
{
sleep 20
echo test
}; exit
(зауважте, що важливо, щоб exitбути на тій же лінії, що і} , що і ви, хоча ви можете також поставити його всередині брекетів безпосередньо перед закриттям).
або:
main() {
sleep 20
echo test
}
main "$@"; exit
Оболонці потрібно буде прочитати сценарій до моменту exit перед цим нічого не почнуть робити. Це гарантує, що оболонка більше не буде прочитана зі сценарію.
Це означає, що весь сценарій буде зберігатися в пам'яті.
Це також може вплинути на розбір сценарію.
Наприклад, у bash:
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
Виведе, що U + 00E9, закодовані в UTF-8. Однак якщо змінити його на:
{
export LC_ALL=fr_FR.UTF-8
echo $'St\ue9phane'
}
\ue9Буде розширено в кодуванні , яка була в дії в той час, коли команда була розібрана , який в цьому випадку , перш ніжexport команда буде виконана.
Також зауважте, що якщо sourceака. команда , з деякими оболонками, у вас виникнуть такі самі проблеми для файлів, що розміщуються.
Це не той випадок, bashхоча sourceкоманда якої читає файл повністю перед його інтерпретацією. Якщо писати bashконкретно, ви можете реально використати це, додавши на початку сценарію:
if [[ ! $already_sourced ]]; then
already_sourced=1
source "$0"; exit
fi
(Я б не покладався на це, хоча, як ви можете собі уявити, майбутні версії bashможуть змінити таку поведінку, яку в даний час можна розглядати як обмеження (bash і AT&T ksh - єдині оболонки, схожі на POSIX, які поводяться так, наскільки це можливо) і already_sourcedтрюк трохи крихкий, оскільки передбачає, що змінної немає в середовищі, не кажучи вже про те, що вона впливає на вміст змінної BASH_SOURCE)