bash: echo: błąd zapisu: przerwane wywołanie systemowe

9

Chcę wygenerować posortowaną listę ze wszystkimi 8-cyfrowymi liczbami - od 00000000 do 99999999. Wpisałem powłokę:

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

odpowiedzią jest

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

Dlaczego dostałem te trzy błędy i źle sformatowany wynik.txt?

używam

GNU bash, wersja 4.4.12 (1) -release (x86_64-pc-linux-gnu)

Debian GNU / Linux 9.6 (odcinek)

Jądro Linux: 4.19.0 # 2 SMP czw. 1 lis 15:31:34 EET 2018 x86_64 GNU / Linux

hon
źródło
2
Nie mogę powstrzymać się od przekonania, że ​​taki sposób działania nie byłby bardziej skuteczny niż seq -w 0 99999999.
Kusalananda
1
Wtedy pytanie jest niekompletne / niepoprawne / źle napisane lub coś innego. Ponieważ skrypt (po zakończeniu z }) działa poprawnie. @ GAD3R
Isaac
1
Uwaga: mogę wyzwolić te błędy prawie na żądanie. Często pojawiają się, gdy zmieniam rozmiar konsoleokna. Taka zmiana rozmiaru jest prawie wystarczająca w moim przypadku, ale nie jest konieczna.
Kamil Maciorowski,
Mogę usunąć | tee result.txti nadal pojawia się błąd.
ctrl-alt-delor
Kolejna uwaga: zewnętrzny plik wykonywalny ( /bin/echow moim przypadku) zamiast echowbudowanego powoduje, że funkcja jest odporna (lub przynajmniej mniej podatna) na ten problem.
Kamil Maciorowski,

Odpowiedzi:

6

Konkretny write error: Interrupted system callbłąd jest generowany, gdy rozmiar okna konsoli zmienia się podczas wykonywania skryptu.

Robiąc:

 trap '' SIGWINCH

uniknie tego.

Zauważ, że a

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

Będzie zarówno szybszy, jak i pozwoli uniknąć SIGWINCHproblemu.

Izaak
źródło
5
Więc co się dzieje ?, dlaczego nie widziałem tego wcześniej ?, Dlaczego błąd zapisu jest właściwą rzeczą?
ctrl-alt-delor
4

Właściwie jest to bug [1] w bash, a to nie zdarza się tylko SIGWINCH, ale także od jakiegokolwiek sygnału dla których pułapka została ustalona:

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

Dzieje się tak, ponieważ bash nie albo) ustawić jego obsługi sygnałów z SA_RESTART(z wyjątkiem SIGCHLDobsługi), lub b) obsłużyć EINTRpodczas wywoływania write()w printfi echopoleceń wbudowanych.

EINTR(„Przerwane wywołanie systemowe”) nie jest sposobem wskazania błędu, ale hackem, który pozwala programiście połączyć blokujące odczyty / zapisy / etc z obsługą sygnałów w głównej pętli. Nigdy nie powinien być wyciekany do użytkownika.

Ten błąd nie pojawia się zbyt często, ponieważ uzyskanie odpowiednich warunków: wyczyn write() powinno to być zrobione przez wbudowane (nie przez zewnętrzne polecenie), powinno wypełnić bufor potoku (czytnik z drugiej strony koniec powinien być znacznie wolniejszy lub w ogóle nie czytać z potoku, ale wciąż żywy ), a skrypt powinien używać pułapek lub należy zmienić rozmiar okna terminala.

A ze względu na różnorodne artefakty implementacji wpływa to tylko na przerwane write() s, nie read()s lub open()s (jak np. Blokowanie open()nazwanego potoku / fifo).

[1] forma tego została już zgłoszona jakiś czas temu.

mosvy
źródło