bash while цикл по файлу не заканчивается при удалении файла

У меня есть цикл while в скрипте bash:

Пример:

while read LINE
do
echo $LINE >> $log_file
done < ./sample_file

У меня вопрос, почему, когда я удаляю файл sample_file во время выполнения скрипта, цикл не заканчивается, и я вижу, что файл log_file обновляется? Как цикл продолжается, пока нет ввода?

3 ответа

Смотрите "Почему файл доступен после удаления в unix?" для превосходного объяснения того, что вы наблюдаете здесь.

Короче...

В основе rm и любой другой команды, которая может появиться для удаления файла, лежит системный вызов unlink. И это называется unlink, not remove или deletefile или чем-то подобным, потому что он не удаляет файл. Он удаляет ссылку (также известную как запись каталога), которая представляет собой связь между файлом и именем в каталоге.

Вы можете использовать функцию truncate уничтожить фактическое содержимое (или shred если вам нужно быть более защищенным), что немедленно остановит выполнение вашего примера цикла.

В Unix файл не удаляется, пока не будет удалена последняя запись в каталоге (например, с rm) и последний дескриптор открытого файла для него закрыт. Смотрите этот вопрос (особенно ответ MarkR) для получения дополнительной информации. В случае вашего скрипта файл открывается как stdin для while read цикл, и пока этот цикл не выйдет (или не закроет свой стандартный ввод), rmесли файл не будет фактически удален с диска.

Вы можете увидеть этот эффект довольно легко, если хотите. Откройте три окна терминала. Во первых запустите команду cat >/tmp/deleteme, Во втором беги tail -f /tmp/deleteme, В третьей, после запуска двух других команд, запустите rm /tmp/deleteme, На данный момент файл был удален, но оба cat а также tail процессы имеют открытые файловые дескрипторы для этого, таким образом это фактически не было удалено. Вы можете доказать это, набрав в первом окне терминала (работает cat), и каждый раз, когда ваш удар возвращается, tail увидит новую строку, добавленную в файл, и отобразит ее во втором окне.

Файл на самом деле не будет удален, пока вы не завершите эти две команды (Control-D завершится cat, но вам нужен Control-C, чтобы убить tail).

Моментная оболочка выполняет цикл while, sample_file содержимое было прочитано, и не имеет значения, существует ли файл после этого момента.

Тестовый скрипт:

$ cat test.sh 
#!/bin/bash

while read line
do
    echo $line
    sleep 1
done < data_file

Тестовый файл:

$ seq 1 10 > data_file

Теперь в одном терминале вы запускаете скрипт, в другом терминале вы идете и удаляете файл data_fileвы все равно увидите цифры от 1 до 10, напечатанные сценарием.

Другие вопросы по тегам