Warum gibt cURL den Fehler "(23) Fehler beim Schreiben des Körpers" zurück?

152

Es funktioniert gut als einzelnes Werkzeug:

curl "someURL"
curl -o - "someURL"

aber es funktioniert nicht in einer Pipeline:

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

es gibt zurück:

(23) Failed writing body

Was ist das Problem beim Weiterleiten des cURL-Ausgangs? Wie kann man die gesamte cURL-Ausgabe puffern und dann damit umgehen?

statisch
quelle
1
Für mich funktioniert es, keine Notwendigkeit zu puffern.
hek2mgl
1
funktioniert das auch in der Pipeline?:curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | tr -d '\n'
statisch
1
Osx-Tags hinzugefügt. Leider kann ich dabei nicht helfen. Ich benutze Linux
hek2mgl
1
Das Problem war die Codierung der Seite (kyrilisch, win-1251). Also muss ichiconv -f ...
statisch
5
Nur als weiterer Hinweis: Meins ist fehlgeschlagen, weil die Festplatte voll war.
Vince Varga

Antworten:

113

Dies geschieht, wenn ein Pipeline-Programm (z. B. grep) die Lese-Pipe schließt, bevor das vorherige Programm das Schreiben der gesamten Seite beendet hat.

In curl "url" | grep -qs foo, sobald grep hat , was es will , es wird der Lesestrom von curl schließen. cURL erwartet dies nicht und gibt den Fehler "Fehlerhafter Schreibkörper" aus.

Eine Problemumgehung besteht darin, den Stream durch ein Zwischenprogramm zu leiten, das immer die gesamte Seite liest, bevor es dem nächsten Programm zugeführt wird.

Z.B

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

tacist ein einfaches Unix-Programm, das die gesamte Eingabeseite liest und die Zeilenreihenfolge umkehrt (daher führen wir sie zweimal aus). Da die gesamte Eingabe gelesen werden muss, um die letzte Zeile zu finden, wird nichts ausgegeben, um grep auszuführen, bis cURL beendet ist. Grep schließt den Lesestream immer noch, wenn es das hat, wonach es sucht, aber es wirkt sich nur auf tac aus, das keinen Fehler ausgibt.

Kaworu
quelle
5
Könnten Sie es nicht einfach cateinmal durchpfeifen? Löst das Problem zumindest für mich.
Benvd
4
Nein. Es kann bei kleinen Dokumenten hilfreich sein, aber wenn es zu groß ist, um in die Pufferkatze zu passen, wird der Fehler erneut -sangezeigt. Sie können alle Fehlermeldungen (und den Fortschritt) stumm schalten, wenn Sie sie nicht benötigen.
Kaworu
8
tac|tacÄndert die Eingabe, wenn die Eingabe nicht mit einem Zeilenvorschub endet oder beispielsweise printf a\\nb\\nc|tac|tacgedruckt wird, a\ncbwo \nsich ein Zeilenvorschub befindet. Sie können sponge /dev/stdoutstattdessen verwenden. Eine andere Option ist printf %s\\n "$(cat)", aber wenn die Eingabe Null-Bytes in anderen Shells als Zsh enthält, werden entweder die Null-Bytes übersprungen oder das Lesen nach dem ersten Null-Byte beendet.
Nisetama
Aus den Dokumenten: CURLE_WRITE_ERROR (23) Beim Schreiben empfangener Daten in eine lokale Datei ist ein Fehler aufgetreten, oder es wurde ein Fehler von einem Schreibrückruf an libcurl zurückgegeben. curl.haxx.se/libcurl/c/libcurl-errors.html
Jordan Stewart
2
Dies sollte als Antwort akzeptiert werden, da es das Problem erklärt, obwohl es keine fähige Lösung bietet, da es tacunter macOS keinen Befehl gibt
Dominik Bucher
48

Für die Vollständigkeit und zukünftige Suche:

Es kommt darauf an, wie cURL den Puffer verwaltet. Der Puffer deaktiviert den Ausgabestream mit der Option -N.

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

user5968839
quelle
8
Es hat funktioniert curl -s https://raw.githubusercontent.com/hermitdave/FrequencyWords/master/content/2016/ro/ro_50k.txt | head -20(ohne dass -sich den gleichen Fehler bekomme).
Dan Dascalescu
24

Eine andere Möglichkeit, wenn Sie die -oOption (Ausgabedatei) verwenden - das Zielverzeichnis existiert nicht.

z.B. wenn du hast -o /tmp/download/abc.txtund / tmp / download nicht existiert.

Stellen Sie daher sicher, dass alle erforderlichen Verzeichnisse im Voraus erstellt wurden / vorhanden sind, und verwenden Sie die --create-dirsOption sowie - ofalls erforderlich

MikeW
quelle
2
Danke, --create-dirs hat das für mich in der ungewöhnlichsten Situation gelöst, konnte nie herausfinden, was los war, aber das war das Ticket!
Rfay
1
Es ist mir gerade in einem ähnlichen Fall passiert. Ich habe vergessen, die Variable $ out für die Ausgabe zu deklarieren. Danke, Mike.
Mincong Huang
8

Es war also ein Problem bei der Codierung. Iconv löst das Problem

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

Sie können dies tun, anstatt die -oOption zu verwenden:

curl [url] > [file]


quelle
Verwenden Sie also nicht die Pipe und erledigen Sie stattdessen die gesamte Arbeit über das Dateisystem? Ich wollte die Ausgabe der Locke mit Rohren verwenden.
statische
6

Ich hatte den gleichen Fehler, aber aus verschiedenen Gründen. In meinem Fall hatte ich eine (tmpfs) Partition mit nur 1 GB Speicherplatz und lud eine große Datei herunter, die schließlich den gesamten Speicher auf dieser Partition füllte , und ich bekam den gleichen Fehler wie Sie.

LLL
quelle
5

In meinem Fall ging dem Server der Speicherplatz aus.

Überprüfen Sie es mit df -k .

Ich wurde auf den Mangel an Speicherplatz aufmerksam gemacht, als ich taczweimal versuchte, durchzuleiten , wie in einer der anderen Antworten beschrieben: https://stackoverflow.com/a/28879552/336694 . Es zeigte mir die Fehlermeldung write error: No space left on device.

HostedMetrics.com
quelle
Ich habe den gleichen Fehler erhalten, weil nicht genügend Speicherplatz in einem Container vorhanden ist. Jeder andere, der das gleiche Problem hat, kann den Speicherplatz in seinen Containern mitdocker system prune
Dave
2

Ich habe diese Fehlermeldung beim Versuch, den Lackcache auf Ubuntu zu installieren, festgestellt. Die Google-Suche hat mich hier wegen des Fehlers gelandet (23) Failed writing bodyund daher eine Lösung veröffentlicht, die für mich funktioniert hat.

Der Fehler tritt auf, wenn der Befehl als root ausgeführt wird curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

Die Lösung besteht darin, apt-key addals Nicht-Root ausgeführt zu werden

curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -
Alles ist gut
quelle
1

Wenn Sie etwas Ähnliches versuchen source <( curl -sS $url )und den (23) Failed writing bodyFehler erhalten, liegt dies daran, dass die Beschaffung einer Prozessersetzung nicht funktioniert bash 3.2(Standardeinstellung für macOS).

Stattdessen können Sie diese Problemumgehung verwenden.

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

Für mich war es eine Erlaubnisfrage. Der Docker-Lauf wird mit einem Benutzerprofil aufgerufen, aber root ist der Benutzer im Container. Die Lösung bestand darin, Curl in / tmp schreiben zu lassen, da dies Schreibberechtigung für alle Benutzer hat, nicht nur für root.

Ich habe die Option -o verwendet.

-o / tmp / file_to_download

lallolu
quelle
-1

In Bash und zsh (und möglicherweise in anderen Shells) können Sie die Prozessersetzung ( Bash / zsh ) verwenden, um eine Datei im laufenden Betrieb zu erstellen, und diese dann als Eingabe für den nächsten Prozess in der Pipelinekette verwenden.

Ich habe beispielsweise versucht, die JSON-Ausgabe von cURL mit jqund zu analysieren less, habe aber den Failed writing bodyFehler erhalten.

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

Als ich es mit Prozessersetzung umgeschrieben habe, hat es funktioniert!

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

Hinweis: jqVerwendet das zweite Argument, um eine Eingabedatei anzugeben

Bonus: Wenn Sie mit jqwie ich und wollen die kolorierte Ausgabe halten in less, verwenden Sie die folgende Befehlszeile statt:

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

(Dank Kowaru für ihre Erklärung , warum Failed writing body auftreten wurde. Doch ihre Lösung mit taczweimal tat für mich nicht. Ich wollte auch eine Lösung finden , die besser für große Dateien und versucht würden skalieren die anderen Fragen als Kommentare bemerkt zu vermeiden auf diese Antwort.)

Robert
quelle