cURL为什么返回错误“(23)书写体失败”?


152

它可以作为单个工具正常工作:

curl "someURL"
curl -o - "someURL"

但它在管道中不起作用:

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

它返回:

(23) Failed writing body

用管道传输cURL输出有什么问题?如何缓冲整个cURL输出然后处理它?


1
对我来说,它有效,无需缓冲。
hek2mgl

1
这也可以在管道中工作吗?:curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | tr -d '\n'
静态

1
添加了osx标签。不幸的是,我对此无能为力。我正在使用Linux
hek2mgl 2013年

1
问题是页面的编码(cyrilic,win-1251)。所以我必须使用iconv -f ...
静态

5
就像另一个提示:我的失败了,因为磁盘已满。
文斯·瓦尔加

Answers:


113

当管道程序(例如grep)在上一个程序完成写入整个页面之前关闭读取管道时,会发生这种情况。

在中curl "url" | grep -qs foo,只要grep拥有所需的内容,它将关闭curl的读取流。cURL不会这样,并且会发出“书写体失败”错误。

一种解决方法是将流通过中间程序传递,该中间程序在将其馈送到下一个程序之前始终读取整个页面。

例如

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

tac是一个简单的Unix程序,它读取整个输入页面并反转行顺序(因此我们将其运行两次)。由于必须读取整个输入才能找到最后一行,因此在cURL完成之前,它不会向grep输出任何内容。Grep拥有所需的内容时,仍会关闭读取流,但只会影响tac,不会发出错误。


5
您能不能简单地通过管道cat一次?至少为我解决了这个问题。
benvd

4
否。这可能对小的文档有所帮助,但是当文档太大而无法放入缓冲猫时,该错误会再次出现-s。如果不需要,可以使用以使所有错误消息(和进度)静音。
卡沃鲁

8
tac|tac如果输入不以换行结尾,则更改输入,例如,在其中输入换行的地方printf a\\nb\\nc|tac|tac打印。您可以改用。另一个选项是,但是当输入在Zsh以外的shell中包含空字节时,它会跳过该空字节或在第一个空字节之后停止读取。a\ncb\nsponge /dev/stdoutprintf %s\\n "$(cat)"
nisetama

从文档:CURLE_WRITE_ERROR(23)将接收到的数据写入本地文件时发生错误,或者从写回调函数返回错误到libcurl。curl.haxx.se/libcurl/c/libcurl-errors.html
Jordan Stewart

2
这应该是可以接受的答案,因为它可以解释问题,但由于tacmacOS上没有命令,它还不能提供功能强大的解决方案
Dominik Bucher

48

为了完整性和将来的搜索:

这与cURL如何管理缓冲区有关,该缓冲区使用-N选项禁用输出流。

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


8
它确实为curl -s https://raw.githubusercontent.com/hermitdave/FrequencyWords/master/content/2016/ro/ro_50k.txt | head -20(没有-s我得到相同的错误)。
Dan Dascalescu

24

如果使用 -o(输出文件)选项 -目标目录不存在。

例如。如果您拥有-o /tmp/download/abc.txt并且/ tmp / download不存在。

因此,请确保事先创建/存在任何必需的目录,并使用--create-dirs选项- o如有必要


2
谢谢,--create-dirs在最不寻常的情况下为我解决了这个问题,无法找出问题所在,但这就是问题所在!
rfay19年

1
只是在类似情况下发生在我身上。我忘了为输出声明变量$ out。谢谢,迈克。
黄敏聪

8

因此,这是编码问题。Iconv解决了这个问题

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

8

您可以执行此操作,而不使用-o选项:

curl [url] > [file]


因此,不使用管道而是通过文件系统完成所有工作吗?我想将curl的输出与管道一起使用。
2013年

6

我有相同的错误,但原因不同。在我的情况下,我的(tmpfs)分区只有1GB的空间,我正在下载大文件,该文件最终占满了该分区上的所有内存,并且出现了与您相同的错误。


5

就我而言,服务器的磁盘空间不足。

用它检查 df -k .

tac如其他答案之一所述,当我尝试通过两次管道传输时,我收到磁盘空间不足的警报:https : //stackoverflow.com/a/28879552/336694。它向我显示了错误消息write error: No space left on device


由于容器中的磁盘空间不足,我收到了相同的错误,因为遇到其他问题的其他人也可以使用以下方法清理容器中的空间docker system prune
Dave

2

尝试在ubuntu上安装清漆缓存时遇到此错误消息。谷歌搜索使我在这里找到错误(23) Failed writing body,因此发布了对我有用的解决方案。

以超级用户身份运行命令时遇到错误 curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

解决方案是以apt-key add非root用户身份运行

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

1

如果您尝试类似的操作source <( curl -sS $url )并遇到(23) Failed writing body错误,那是因为寻找替代品在bash 3.2(macOS的默认设置)。

而是,您可以使用此替代方法。

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

0

对我来说,这是许可问题。使用用户配置文件调用Docker运行,但root是容器内的用户。解决方案是使curl向/ tmp写入,因为它对所有用户(而不仅仅是root)具有写权限。

我使用了-o选项。

-o / tmp / file_to_download


-1

在Bash和zsh(可能还有其他shell)中,您可以使用进程替换(Bash / zsh)动态创建文件,然后将其用作管道链中下一个进程的输入。

例如,我试图使用jq和解析来自cURL的JSON输出less,但Failed writing body出现错误。

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

当我使用进程替换重写它时,它起作用了!

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

注意:jq使用其第二个参数指定输入文件

奖励:如果您jq像我一样使用并且希望将彩色输出保留在less,请改用以下命令行:

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

(感谢Kowaru解释了为什么 Failed writing body会发生这种情况。但是,他们使用tac两次的解决方案对我来说不起作用。我还想找到一个更适合大文件扩展的解决方案,并尝试避免将其他问题注释为注释这个答案。)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.