Perché cURL restituisce l'errore "(23) Impossibile scrivere il corpo"?


153

Funziona bene come un singolo strumento:

curl "someURL"
curl -o - "someURL"

ma non funziona in una pipeline:

curl "someURL" | tr -d '\n'
curl -o - "someURL" | tr -d '\n'

ritorna:

(23) Failed writing body

Qual è il problema con il piping dell'output cURL? Come bufferizzare l'intero output cURL e quindi gestirlo?


1
Per me funziona, non c'è bisogno di buffer.
hek2mgl,

1
funziona anche in cantiere ?:curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | tr -d '\n'
statico

1
Aggiunti tag osx. Purtroppo non posso farci niente. Sto usando Linux
hek2mgl

1
il problema era la codifica della pagina (cirillico, win-1251). Quindi devo usareiconv -f ...
statico

5
Proprio come un altro suggerimento: il mio non è riuscito, perché il disco era pieno.
Vince Varga,

Risposte:


113

Ciò accade quando un programma con pipe (ad esempio grep) chiude la pipe di lettura prima che il programma precedente abbia finito di scrivere l'intera pagina.

In curl "url" | grep -qs foo, non appena grep ha quello che vuole, chiuderà il flusso di lettura dall'arricciatura. cURL non si aspetta questo ed emette l'errore "Failed writing body".

Una soluzione alternativa consiste nel reindirizzare il flusso attraverso un programma intermedio che legge sempre l'intera pagina prima di inviarlo al programma successivo.

Per esempio

curl "url" | tac | tac | grep -qs foo

tacè un semplice programma Unix che legge l'intera pagina di input e inverte l'ordine delle righe (quindi lo eseguiamo due volte). Poiché deve leggere l'intero input per trovare l'ultima riga, non emetterà nulla per grep fino a quando cURL non sarà terminato. Grep chiuderà comunque il flusso di lettura quando ha quello che sta cercando, ma influenzerà solo tac, che non emette un errore.


5
Non potresti semplicemente convogliarlo catuna volta? Risolve il problema per me, almeno.
benvd,

5
No. Potrebbe essere utile con documenti di piccole dimensioni, ma quando è troppo grande per essere inserito nel buffer cat, l'errore riapparirà. È possibile utilizzare -sper mettere a tacere tutti i messaggi di errore (e i progressi) se non sono necessari.
Kaworu,

9
tac|taccambia l'input se l'input non termina con un avanzamento riga o, ad esempio, printf a\\nb\\nc|tac|tacstampa a\ncbdove si \ntrova un avanzamento riga. Puoi usare sponge /dev/stdoutinvece. Un'altra opzione è printf %s\\n "$(cat)", ma quando l'input contiene byte null in shell diverse da Zsh, questo salta i byte null o interrompe la lettura dopo il primo byte null.
nisetama,

Dai documenti: CURLE_WRITE_ERROR (23) Si è verificato un errore durante la scrittura dei dati ricevuti in un file locale o un errore è stato restituito a libcurl da un callback in scrittura. curl.haxx.se/libcurl/c/libcurl-errors.html
Jordan Stewart

3
Questa dovrebbe essere una risposta accettata perché spiega il problema, tuttavia non fornisce una soluzione capace in quanto non vi è alcun taccomando su macOS
Dominik Bucher

49

Per completezza e ricerche future:

Dipende da come cURL gestisce il buffer, il buffer disabilita il flusso di output con l'opzione -N.

Esempio: curl -s -N "URL" | grep -q Welcome


8
Ha funzionato per curl -s https://raw.githubusercontent.com/hermitdave/FrequencyWords/master/content/2016/ro/ro_50k.txt | head -20(senza -sche ottenga lo stesso errore).
Dan Dascalescu,

24

Un'altra possibilità, se si utilizza il -o opzione (file di output) - la directory di destinazione non esiste.

per esempio. se hai -o /tmp/download/abc.txte / tmp / download non esiste.

Quindi, assicurarsi che tutte le directory richieste siano state create / esistere in anticipo, utilizzare l' --create-dirsopzione e - ose necessario


2
Grazie, --create-dirs mi ha risolto questo problema nella situazione più insolita, non riuscivo mai a capire cosa non andava, ma questo era il biglietto!
rfay,

1
Mi è appena successo in un caso simile. Ho dimenticato di dichiarare la variabile $ out per l'output. Grazie Mike.
Mincong Huang,

8

Quindi era un problema di codifica. Iconv risolve il problema

curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | iconv -f windows-1251 | tr -dc '[:print:]' | ...

8

Puoi farlo invece di usare l' -oopzione:

curl [url] > [file]


quindi, non usare la pipe e invece fare tutto il lavoro sul file system? Volevo usare l'output del ricciolo con i tubi.
statico

6

Ho avuto lo stesso errore ma per motivi diversi. Nel mio caso avevo una partizione (tmpfs) con solo 1 GB di spazio e stavo scaricando un grosso file che alla fine ha riempito tutta la memoria su quella partizione e ho avuto lo stesso errore di te.


5

Nel mio caso il server ha esaurito lo spazio su disco.

Controllalo con df -k .

Sono stato avvisato della mancanza di spazio su disco quando ho provato a eseguire il piping tacdue volte, come descritto in una delle altre risposte: https://stackoverflow.com/a/28879552/336694 . Mi ha mostrato il messaggio di errore write error: No space left on device.


Ho ricevuto lo stesso errore a causa di esaurire lo spazio su disco all'interno di un contenitore, per chiunque altro anche colpire lo stesso problema può ripulire lo spazio all'interno dei loro contenitori condocker system prune
Dave

2

Ho riscontrato questo messaggio di errore durante il tentativo di installare la cache di vernice su Ubuntu. La ricerca su Google mi ha portato qui per l'errore (23) Failed writing body, quindi pubblicando una soluzione che ha funzionato per me.

Il bug si verifica durante l'esecuzione del comando come root curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

la soluzione è eseguire apt-key addcome non root

curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

1

Se stai provando qualcosa di simile source <( curl -sS $url )e stai ricevendo l' (23) Failed writing bodyerrore, è perché l'approvvigionamento di una sostituzione del processo non funzionabash 3.2 (impostazione predefinita per macOS).

È invece possibile utilizzare questa soluzione alternativa.

source /dev/stdin <<<"$( curl -sS $url )"

0

Per me, è stato un problema di autorizzazione. L'esecuzione di Docker viene chiamata con un profilo utente ma root è l'utente all'interno del contenitore. La soluzione consisteva nel fare arricciare la scrittura su / tmp poiché ha l'autorizzazione di scrittura per tutti gli utenti, non solo per il root.

Ho usato l'opzione -o.

-o / tmp / file_to_download


-1

In Bash e zsh (e forse altre shell), è possibile utilizzare la sostituzione di processo ( Bash / zsh ) per creare un file al volo, quindi utilizzarlo come input per il processo successivo nella catena della pipeline.

Ad esempio, stavo cercando di analizzare l'output JSON da cURL usando jqe less, ma stavo ottenendo l' Failed writing bodyerrore.

# Note: this does NOT work
curl https://gitlab.com/api/v4/projects/ | jq | less

Quando l'ho riscritto usando la sostituzione del processo, ha funzionato!

# this works!
jq "" <(curl https://gitlab.com/api/v4/projects/) | less

Nota: jqusa il suo secondo argomento per specificare un file di input

Bonus: Se si sta utilizzando jqcome me e vuole mantenere l'uscita colorized in less, utilizzare la seguente riga di comando:

jq -C "" <(curl https://gitlab.com/api/v4/projects/) | less -r

(Grazie a Kowaru per la spiegazione del perché si Failed writing body stava verificando. Tuttavia, la loro soluzione di utilizzo tacdoppio non ha funzionato per me. Volevo anche trovare una soluzione che si ridimensionasse meglio per file di grandi dimensioni e cercasse di evitare gli altri problemi indicati come commenti a quella risposta.)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.