bash: echo: ошибка записи: прерван системный вызов

9

Я хочу создать отсортированный список со всеми 8-значными числами - от 00000000 до 99999999. Я набрал в оболочке:

f() {
 while IFS="" read -r line; do
   for i in {0..9}; do 
       echo "$line$i";
   done;
 done
}

echo | f | f | f | f | f | f | f | f | tee result.txt | wc -l

ответ

bash: echo: write error: Interrupted system call
bash: echo: write error: Interrupted system call
bash: echo: write error: Interrupted system call
99998890

Почему я получил эти три ошибки и искаженный файл result.txt?

я использую

GNU bash, версия 4.4.12 (1) -релиз (x86_64-pc-linux-gnu)

Debian GNU / Linux 9.6 (растянутая)

Ядро Linux: 4.19.0 # 2 SMP четверг, 1 ноября 15:31:34 EET 2018 x86_64 GNU / Linux

хон
источник
2
Я не могу не чувствовать, что этот способ сделать это не будет более эффективным, чем seq -w 0 99999999.
Кусалананда
1
Тогда вопрос неполный / неправильный / плохо написанный или что-то еще. Потому что скрипт (когда завершено с }) работает правильно. @ GAD3R
Исаак
1
Примечание: я могу вызвать эти ошибки почти по требованию. Они часто появляются, когда я изменяю размер konsoleокна. Такое изменение размера почти достаточно в моем случае, но не обязательно.
Камиль Мачоровский
Я могу удалить | tee result.txt, и все еще получить ошибку.
Ctrl-Alt-Delor
Еще одно замечание: внешний исполняемый файл ( /bin/echoв моем случае) вместо echoвстроенного делает функцию невосприимчивой (или, по крайней мере, менее склонной) к этой проблеме.
Камиль Мачоровский

Ответы:

6

Конкретная write error: Interrupted system callошибка генерируется при изменении размера окна консоли во время выполнения скрипта.

Делать:

 trap '' SIGWINCH

буду избегать этого.

Обратите внимание, что

 seq 99999999 >result.txt; wc -l <result.txt

Будет и быстрее, и позволит избежать SIGWINCHпроблемы.

Исаак
источник
5
Итак, что происходит? Почему я не видел этого раньше? Почему ошибка записи - правильная вещь?
Ctrl-Alt-Delor
4

Это на самом деле ошибка [1] в bash, и это происходит не только SIGWINCH, но и для любого сигнала, для которого была установлена ​​ловушка:

{ pid=$BASHPID; trap : USR1; (sleep 1; kill -USR1 $pid) &
         printf %0100000d 1; } | sleep 3600
bash: printf: write error: Interrupted system call

Это происходит потому, что bashне удается либо a) установить свои обработчики сигналов с помощью SA_RESTART(кроме SIGCHLDобработчика), либо b) обработать EINTRпри вызове write()в printfи echoвстроенные функции.

EINTR(«Прерванный системный вызов») - это не способ обозначить состояние ошибки, а взлом, который позволяет программисту комбинировать блокировку чтения / записи / и т. Д. С обработкой сигналов в основном цикле. Он никогда не должен быть передан пользователю.

Эта ошибка появляется не слишком часто, потому что это довольно сложная задача - установить правильные условия: это write()должно быть сделано встроенным (а не внешней командой), оно должно заполнить буфер канала (читатель на другом конец должен быть намного медленнее или вообще не читать из канала, но все еще жив ), и сценарий должен использовать ловушки или окно терминала должно быть изменено.

А из-за разнообразных артефактов реализации это влияет только на прерванные write()s, а не read()s или open()s (как, например, блокирование open()именованного канала / fifo).

[1] форма об этом уже сообщалось некоторое время назад.

mosvy
источник