¿Por qué cURL devuelve el error "(23) Error al escribir el cuerpo"?

153

Funciona bien como una sola herramienta:

curl "someURL"
curl -o - "someURL"

pero no funciona en una tubería:

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

vuelve:

(23) Failed writing body

¿Cuál es el problema con la tubería de salida de cURL? ¿Cómo almacenar en búfer toda la salida de cURL y luego manejarla?

estático
fuente
1
Para mí funciona, no hay necesidad de amortiguar.
hek2mgl
1
¿esto también funciona en la tubería ?:curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | tr -d '\n'
estático
1
Se agregaron etiquetas osx. Lamentablemente no puedo ayudar con esto. Estoy usando Linux
hek2mgl
1
El problema era la codificación de la página (cirílico, win-1251). Así que debo usariconv -f ...
estática
55
Como otra pista: la mía falló porque el disco estaba lleno.
Vince Varga

Respuestas:

113

Esto sucede cuando un programa canalizado (por ejemplo, grep) cierra la canalización de lectura antes de que el programa anterior termine de escribir toda la página.

En curl "url" | grep -qs foo, tan pronto como grep tenga lo que quiere, cerrará la secuencia de lectura de curl. cURL no espera esto y emite el error "Error al escribir el cuerpo".

Una solución alternativa es canalizar la transmisión a través de un programa intermediario que siempre lee toda la página antes de pasarla al siguiente programa.

P.ej

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

taces un programa simple de Unix que lee toda la página de entrada e invierte el orden de las líneas (por lo tanto, lo ejecutamos dos veces). Debido a que tiene que leer toda la entrada para encontrar la última línea, no generará nada para grep hasta que cURL haya terminado. Grep seguirá cerrando el flujo de lectura cuando tenga lo que está buscando, pero solo afectará a tac, que no emite un error.

Kaworu
fuente
55
¿No podrías simplemente pasarlo catuna vez? Resuelve el problema para mí, al menos.
benvd
55
No. Podría ayudar con documentos pequeños, pero cuando es demasiado grande para caber en el búfer, el error volverá a aparecer. Puede usarlo -spara silenciar todos los mensajes de error (y progreso) si no los necesita.
Kaworu
9
tac|taccambia la entrada si la entrada no termina con un salto de línea o, por ejemplo, printf a\\nb\\nc|tac|tacimprime a\ncbdónde \nhay un salto de línea. Puedes usar sponge /dev/stdouten su lugar. Otra opción es printf %s\\n "$(cat)", pero cuando la entrada contiene bytes nulos en shells distintos de Zsh, eso omite los bytes nulos o deja de leer después del primer byte nulo.
nisetama
De los documentos: CURLE_WRITE_ERROR (23) Se produjo un error al escribir los datos recibidos en un archivo local, o se devolvió un error a libcurl desde una devolución de llamada de escritura. curl.haxx.se/libcurl/c/libcurl-errors.html
Jordan Stewart
3
Esta respuesta debe aceptarse porque explica el problema, aunque no proporciona una solución capaz ya que no hay un taccomando en macOS
Dominik Bucher
49

Para completar y futuras búsquedas:

Es una cuestión de cómo cURL administra el búfer, el búfer deshabilita el flujo de salida con la opción -N.

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

usuario5968839
fuente
8
Funcionó para curl -s https://raw.githubusercontent.com/hermitdave/FrequencyWords/master/content/2016/ro/ro_50k.txt | head -20(sin que -sme salga el mismo error).
Dan Dascalescu
24

Otra posibilidad, si usa la -oopción (archivo de salida), el directorio de destino no existe.

p.ej. si tiene -o /tmp/download/abc.txty / tmp / download no existe.

Por lo tanto, asegúrese de que los directorios necesarios se creen / existan de antemano, use la --create-dirsopción y, osi es necesario

MikeW
fuente
2
Gracias, --create-dirs resolvió esto por mí en la situación más inusual, nunca podría descubrir qué estaba mal, ¡pero este fue el boleto!
rfay
1
Simplemente me sucedió en un caso similar. Olvidé declarar la variable $ out para la salida. Gracias Mike.
Mincong Huang
8

Entonces fue un problema de codificación. Iconv resuelve el problema

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

Puede hacer esto en lugar de usar la -oopción:

curl [url] > [file]


fuente
entonces, ¿no usas la tubería y en su lugar haces todo el trabajo sobre el sistema de archivos? Quería usar la salida del rizo con tuberías.
estático
6

Tuve el mismo error pero por diferentes razones. En mi caso, tenía una partición (tmpfs) con solo 1GB de espacio y estaba descargando un archivo grande que finalmente llenó toda la memoria de esa partición y obtuve el mismo error que usted.

LLL
fuente
5

El servidor se quedó sin espacio en disco, en mi caso.

Compruébalo con df -k .

Me alertaron de la falta de espacio en disco cuando intenté pasar tacdos veces, como se describe en una de las otras respuestas: https://stackoverflow.com/a/28879552/336694 . Me mostró el mensaje de error write error: No space left on device.

HostedMetrics.com
fuente
Recibí el mismo error debido a la falta de espacio en el disco dentro de un contenedor, ya que cualquier otra persona que también tenga el mismo problema puede limpiar el espacio dentro de sus contenedores condocker system prune
Dave
2

Encontré este mensaje de error al intentar instalar la memoria caché de barniz en ubuntu. La búsqueda en Google me trajo el error (23) Failed writing bodyaquí, por lo tanto, publiqué una solución que funcionó para mí.

El error se encuentra al ejecutar el comando como root curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

la solución es correr apt-key addcomo no root

curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -
Todo es variado
fuente
1

Si está intentando algo similar source <( curl -sS $url )y obtiene el (23) Failed writing bodyerror, es porque el abastecimiento de una sustitución de proceso no funciona bash 3.2(el valor predeterminado para macOS).

En su lugar, puede usar esta solución alternativa.

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

Para mí, fue un problema de permiso. Docker run se llama con un perfil de usuario, pero root es el usuario dentro del contenedor. La solución fue hacer curl write to / tmp ya que tiene permiso de escritura para todos los usuarios, no solo root.

Usé la opción -o.

-o / tmp / file_to_download

lallolu
fuente
-1

En Bash y zsh (y quizás otros shells), puede usar la sustitución de procesos ( Bash / zsh ) para crear un archivo sobre la marcha, y luego usarlo como entrada para el siguiente proceso en la cadena de canalización.

Por ejemplo, estaba tratando de analizar la salida JSON de cURL usando jqy less, pero recibía el Failed writing bodyerror.

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

Cuando lo reescribí usando la sustitución del proceso, ¡funcionó!

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

Nota: jqusa su segundo argumento para especificar un archivo de entrada

Bono: Si usted está utilizando jqcomo yo y quiere mantener la salida coloreada en less, utilice la siguiente línea de comandos en su lugar:

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

(Gracias a Kowaru por su explicación de por qué Failed writing body estaba ocurriendo. Sin embargo, su solución de usar tacdos veces no funcionó para mí. También quería encontrar una solución que escalara mejor para archivos grandes y trata de evitar los otros problemas señalados como comentarios a esa respuesta.)

Robert
fuente