Pourquoi cURL renvoie-t-il l'erreur «(23) Failed writing body»?

153

Cela fonctionne bien comme un seul outil:

curl "someURL"
curl -o - "someURL"

mais cela ne fonctionne pas dans un pipeline:

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

il renvoie:

(23) Failed writing body

Quel est le problème avec la canalisation de la sortie cURL? Comment mettre en mémoire tampon toute la sortie cURL puis la gérer?

statique
la source
1
Pour moi ça marche, pas besoin de tampon.
hek2mgl
1
cela fonctionne-t-il aussi dans le pipeline?:curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | tr -d '\n'
statique
1
Ajout de balises osx. Malheureusement, je ne peux pas vous aider. J'utilise Linux
hek2mgl
1
le problème était l'encodage de la page (cyrilique, win-1251). Je dois donc utilisericonv -f ...
statique
5
Juste un autre indice: le mien a échoué, car le disque était plein.
Vince Varga

Réponses:

113

Cela se produit quand un programme canalisé (par exemple grep) ferme le tube de lecture avant que le programme précédent n'ait fini d'écrire la page entière.

Dans curl "url" | grep -qs foo, dès que grep a ce qu'il veut, il fermera le flux de lecture de curl. cURL ne s'y attend pas et émet l'erreur «Échec de l'écriture du corps».

Une solution de contournement consiste à diriger le flux via un programme intermédiaire qui lit toujours la page entière avant de l'envoyer au programme suivant.

Par exemple

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

tacest un simple programme Unix qui lit toute la page d'entrée et inverse l'ordre des lignes (donc nous l'exécutons deux fois). Comme il doit lire toute l'entrée pour trouver la dernière ligne, il ne sortira rien vers grep tant que cURL ne sera pas terminé. Grep fermera toujours le flux de lecture lorsqu'il aura ce qu'il recherche, mais cela n'affectera que tac, qui n'émet pas d'erreur.

Kaworu
la source
5
Ne pourriez-vous pas le faire passer catune seule fois? Résout le problème pour moi, au moins.
benvd
5
Non. Cela peut aider avec les petits documents, mais quand il est trop grand pour tenir dans le tampon que cat utilise, l'erreur réapparaîtra. Vous pouvez utiliser -spour faire taire tous les messages d'erreur (et la progression) si vous n'en avez pas besoin.
Kaworu
9
tac|tacmodifie l'entrée si l'entrée ne se termine pas par un saut de ligne, ou par exemple printf a\\nb\\nc|tac|tacimprime a\ncb\nest un saut de ligne. Vous pouvez utiliser à la sponge /dev/stdoutplace. Une autre option est printf %s\\n "$(cat)", mais lorsque l'entrée contient des octets nuls dans des shells autres que Zsh, cela ignore les octets nuls ou arrête la lecture après le premier octet nul.
nisetama
À partir de la documentation: CURLE_WRITE_ERROR (23) Une erreur s'est produite lors de l'écriture des données reçues dans un fichier local, ou une erreur a été renvoyée à libcurl à partir d'un rappel d'écriture. curl.haxx.se/libcurl/c/libcurl-errors.html
Jordan Stewart
3
Cela devrait être une réponse acceptée car cela explique le problème, mais cela ne fournit pas de solution capable car il n'y a pas de taccommande sur macOS
Dominik Bucher
49

Pour l'exhaustivité et les recherches futures:

C'est une question de comment cURL gère le tampon, le tampon désactive le flux de sortie avec l'option -N.

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

user5968839
la source
8
Cela a fonctionné pour curl -s https://raw.githubusercontent.com/hermitdave/FrequencyWords/master/content/2016/ro/ro_50k.txt | head -20(sans -sque j'obtienne la même erreur).
Dan Dascalescu le
24

Une autre possibilité, si vous utilisez le -o option (fichier de sortie) - le répertoire de destination n'existe pas.

par exemple. si vous avez -o /tmp/download/abc.txtet / tmp / download n'existe pas.

Par conséquent, assurez-vous que tous les répertoires requis sont créés / existent au préalable, utilisez l' --create-dirsoption ainsi que - osi nécessaire

MikeW
la source
2
Merci, --create-dirs a résolu cela pour moi dans la situation la plus inhabituelle, je n'ai jamais pu comprendre ce qui n'allait pas, mais c'était le ticket!
rfay
1
Cela m'est arrivé dans un cas similaire. J'ai oublié de déclarer la variable $ out pour la sortie. Merci, Mike.
Mincong Huang
8

C'était donc un problème d'encodage. Iconv résout le problème

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

Vous pouvez le faire au lieu d'utiliser l' -ooption:

curl [url] > [file]


la source
donc, ne pas utiliser le tuyau et à la place faire tout le travail sur le système de fichiers? Je voulais utiliser la sortie de curl avec des tuyaux.
statique
6

J'ai eu la même erreur mais pour une raison différente. Dans mon cas, j'avais une partition (tmpfs) avec seulement 1 Go d'espace et je téléchargeais un gros fichier qui a finalement rempli toute la mémoire de cette partition et j'ai eu la même erreur que vous.

JE VAIS
la source
5

Le serveur a manqué d'espace disque, dans mon cas.

Vérifiez-le avec df -k .

J'ai été alerté du manque d'espace disque lorsque j'ai essayé de passer tacdeux fois, comme décrit dans l'une des autres réponses: https://stackoverflow.com/a/28879552/336694 . Il m'a montré le message d'erreur write error: No space left on device.

HostedMetrics.com
la source
J'ai reçu la même erreur en raison d'un manque d'espace disque dans un conteneur, car toute autre personne qui rencontre également le même problème peut nettoyer l'espace dans ses conteneurs avecdocker system prune
Dave
2

J'ai rencontré ce message d'erreur en essayant d'installer le cache de vernis sur ubuntu. La recherche sur Google m'a permis de déceler l'erreur (23) Failed writing body, d'où la publication d'une solution qui a fonctionné pour moi.

Le bogue est rencontré lors de l'exécution de la commande en tant que root curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

la solution est de fonctionner en apt-key addtant que non root

curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -
Tout est Vаиітy
la source
1

Si vous essayez quelque chose de similaire source <( curl -sS $url )et que vous obtenez l' (23) Failed writing bodyerreur, c'est parce que l'approvisionnement d'une substitution de processus ne fonctionne pas dansbash 3.2 (par défaut pour macOS).

Au lieu de cela, vous pouvez utiliser cette solution de contournement.

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

Pour moi, c'était une question de permission. L'exécution de Docker est appelée avec un profil utilisateur mais root est l'utilisateur à l'intérieur du conteneur. La solution était de faire en sorte que curl écrive dans / tmp puisque cela a l'autorisation d'écriture pour tous les utilisateurs, pas seulement root.

J'ai utilisé l'option -o.

-o / tmp / file_to_download

Lallolu
la source
-1

Dans Bash et zsh (et peut-être dans d'autres shells), vous pouvez utiliser la substitution de processus ( Bash / zsh ) pour créer un fichier à la volée, puis l'utiliser comme entrée du processus suivant dans la chaîne de pipeline.

Par exemple, j'essayais d'analyser la sortie JSON de cURL en utilisant jqet less, mais j'obtenais l' Failed writing bodyerreur.

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

Quand je l'ai réécrit en utilisant la substitution de processus, cela a fonctionné!

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

Remarque: jqutilise son 2ème argument pour spécifier un fichier d'entrée

Bonus: Si vous utilisez jqcomme moi et que vous voulez garder la sortie colorisée en less, utilisez la ligne de commande suivante à la place:

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

(Merci à Kowaru pour leur explication sur les raisons de cet incidentFailed writing body . Cependant, leur solution consistant à utiliser tacdeux fois n'a pas fonctionné pour moi. Je voulais également trouver une solution qui serait mieux adaptée aux fichiers volumineux et essaie d'éviter les autres problèmes mentionnés dans les commentaires. à cette réponse.)

Robert
la source