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

Чому я отримав ці три помилки та неправильно сформований результат.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

уникне цього.

Зауважте, що a

 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не вдається а) встановити обробники сигналів SA_RESTART(за винятком SIGCHLDобробника), або б) обробляти під EINTRчас виклику write()в printfі echoвбудованих.

EINTR("Перерваний системний виклик") - це не спосіб вказувати на стан помилки, а хак, який дозволяє програмісту поєднувати блокування читання / запису / тощо з обробкою сигналів в основному циклі. Він ніколи не повинен просочуватися до користувача.

Ця помилка не з’являється занадто часто, тому що це досить подвиг, щоб створити правильні умови: це write()має робити вбудований (а не зовнішня команда), він повинен заповнювати буфер труб (зчитувач з іншого кінець повинен бути набагато повільнішим або взагалі не читати з труби, але все ще живий ), а сценарій повинен використовувати пастки або змінити вікно терміналу.

А через різноманітні артефакти реалізації, це впливає лише на перервані write()s, а не read()s або open()s (як, наприклад, блокування open()названої труби / fifo).

[1] про форму про це вже повідомлялося деякий час тому.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.