Я писал сценарий bash и случайно обновил код (сохранил файл сценария на диске), пока сценарий ожидал некоторого ввода в while
цикле. После того, как я вернулся в терминал и продолжил предыдущий вызов скрипта, bash выдал ошибку о синтаксисе файла:
/home/aularon/bin/script: line 58: unexpected EOF while looking for matching `"'
/home/aularon/bin/script: line 67: syntax error: unexpected end of file
Поэтому я попытался сделать следующее:
1-й: создайте скрипт, self-update.sh
давайте назовем его:
#!/bin/bash
fname=$(mktemp)
cat $0 | sed 's/BEFORE\./AFTER!./' > $fname
cp $fname $0
rm -f $fname
echo 'String: BEFORE.';
Сценарий читает код, изменяя слово «ДО» на «ПОСЛЕ», а затем переписывает себя с новым кодом.
2-ой Запустите это:
chmod +x self-update.sh
./self-update.sh
3-е чудо ...
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Я бы даже не догадался, что при одном и том же вызове он выдаст ПОСЛЕ! На втором запуске точно, но не на первом.
Итак, мой вопрос: это намеренно (по замыслу)? или это из-за того, как bash запускает скрипт? Строка за строкой или команда за командой. Есть ли польза от такого поведения? Любой пример этого?
Редактировать: я попытался переформатировать файл, чтобы поместить все команды в одну строку, он не работает сейчас:
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;echo 'String: BEFORE.';
Вывод:
aularon@aularon-laptop:~$ ./self-update.sh #First invocation
String: BEFORE.
aularon@aularon-laptop:~$ ./self-update.sh #Second invocation
String: AFTER!.
При перемещении echo
строки на следующую строку, отделив ее от cp
вызова rewriting ( ):
#!/bin/bash
fname=$(mktemp);cat $0 | sed 's/BEFORE\./AFTER!./' > $fname;cp $fname $0;rm -f $fname;
echo 'String: BEFORE.';
И теперь это работает снова:
aularon@aularon-laptop:~$ ./self-update.sh
String: AFTER!.
Ответы:
Это по замыслу. Bash читает сценарии кусками. Таким образом, он будет читать часть скрипта, запускать любые возможные строки и затем читать следующий фрагмент.
Итак, вы сталкиваетесь с чем-то вроде этого:
Еще более проблематичным становится то, что если вы редактируете что-либо до байта 256. Допустим, вы удалили пару строк. Тогда данные в сценарии, которые были в байте 256, теперь находятся где-то еще, скажем, в байте 156 (на 100 байтов ранее). Из-за этого, когда bash продолжит читать, он получит то, что изначально было 356.
Это всего лишь пример. Bash не обязательно читает 256 байтов за раз. Я не знаю точно, сколько он читает за раз, но это не имеет значения, поведение остается прежним.
источник
stat
файл, чтобы увидеть, изменился ли он. Нетlseek
звонков.echo foo
изменилосьecho bar
во времяsleep
. Это ведет себя так же, как в версии 2, так что я не думаю, что это проблема версии.