Tại sao cURL trả về lỗi Lỗi (23) Không thể viết cơ thể?


152

Nó hoạt động tốt như một công cụ duy nhất:

curl "someURL"
curl -o - "someURL"

nhưng nó không hoạt động trong một đường ống dẫn:

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

nó trở lại:

(23) Failed writing body

Vấn đề với đường ống đầu ra cURL là gì? Làm thế nào để đệm toàn bộ đầu ra cURL và sau đó xử lý nó?


1
Đối với tôi nó hoạt động, không cần phải đệm.
hek2mgl

1
cái này có hoạt động trong đường ống không?:curl 'http://www.multitran.ru/c/m.exe?CL=1&s=hello&l1=1' | tr -d '\n'
tĩnh

1
Đã thêm thẻ osx. Thật không may, tôi không thể giúp với điều này. Tôi đang sử dụng Linux
hek2mgl

1
vấn đề là mã hóa trang (cyrilic, win-1251). Vì vậy, tôi phải sử dụngiconv -f ...
tĩnh

5
Cũng như một gợi ý khác: Của tôi thất bại, vì đĩa đã đầy.
Vince Varga

Câu trả lời:


113

Điều này xảy ra khi một chương trình đường ống (ví dụ grep) đóng ống đọc trước khi chương trình trước kết thúc việc viết toàn bộ trang.

Trong curl "url" | grep -qs foo, ngay khi grep có những gì nó muốn, nó sẽ đóng luồng đọc từ curl. cURL không mong đợi điều này và phát ra lỗi "Cơ thể viết không thành công".

Một cách giải quyết là dẫn luồng thông qua một chương trình trung gian luôn đọc toàn bộ trang trước khi đưa nó vào chương trình tiếp theo.

Ví dụ

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

taclà một chương trình Unix đơn giản đọc toàn bộ trang đầu vào và đảo ngược thứ tự dòng (do đó chúng tôi chạy nó hai lần). Bởi vì nó phải đọc toàn bộ đầu vào để tìm dòng cuối cùng, nó sẽ không xuất bất cứ thứ gì cho grep cho đến khi cURL kết thúc. Grep vẫn sẽ đóng luồng đọc khi nó có thứ mà nó đang tìm kiếm, nhưng nó sẽ chỉ ảnh hưởng đến tac, không phát ra lỗi.


5
Bạn có thể không chỉ đơn giản là đưa nó qua catmột lần? Giải quyết vấn đề cho tôi, ít nhất.
benvd

4
Không. Nó có thể giúp với các tài liệu nhỏ nhưng khi nó quá lớn để phù hợp với bộ đệm, sử dụng lỗi sẽ xuất hiện lại. Bạn có thể sử dụng -sđể tắt tất cả các thông báo lỗi (và tiến trình) nếu bạn không cần chúng.
Kaworu

8
tac|tacthay đổi đầu vào nếu đầu vào không kết thúc bằng nguồn cấp dữ liệu hoặc ví dụ printf a\\nb\\nc|tac|tacin a\ncbở đâu \nlà nguồn cấp dữ liệu. Bạn có thể sử dụng sponge /dev/stdoutthay thế. Một tùy chọn khác là printf %s\\n "$(cat)", nhưng khi đầu vào chứa các byte rỗng trong các shell khác với Zsh, thì bỏ qua các byte null hoặc dừng đọc sau byte null đầu tiên.
nisetama

Từ các tài liệu: CURLE_WRITE_ERROR (23) Đã xảy ra lỗi khi ghi dữ liệu nhận vào tệp cục bộ hoặc lỗi được trả về libcurl từ lệnh gọi lại ghi. curl.haxx.se/libcurl/c/libcurl-errors.html
Jordan Stewart

2
Điều này nên được chấp nhận câu trả lời vì nó giải thích vấn đề, vì nó không cung cấp giải pháp có khả năng vì không có taclệnh nào trên macOS
Dominik Bucher

48

Để hoàn thiện và tìm kiếm trong tương lai:

Đó là vấn đề làm thế nào cURL quản lý bộ đệm, bộ đệm vô hiệu hóa luồng đầu ra với tùy chọn -N.

Thí dụ: curl -s -N "URL" | grep -q Welcome


8
Nó đã làm việc cho curl -s https://raw.githubusercontent.com/hermitdave/FrequencyWords/master/content/2016/ro/ro_50k.txt | head -20(mà -stôi không nhận được cùng một lỗi).
Dan Dascalescu

24

Một khả năng khác, nếu sử dụng -otùy chọn (tệp đầu ra) - thư mục đích không tồn tại.

ví dụ. nếu bạn có -o /tmp/download/abc.txtvà / tmp / tải xuống không tồn tại.

Do đó, đảm bảo mọi thư mục cần thiết được tạo / tồn tại trước đó, sử dụng --create-dirstùy chọn cũng như - onếu cần


2
Cảm ơn, - các tác giả đã giải quyết vấn đề này cho tôi trong tình huống bất thường nhất, không bao giờ có thể hiểu được chuyện gì đã xảy ra, nhưng đây là vé!
rfay

1
Nó chỉ xảy ra với tôi trong trường hợp tương tự. Tôi quên khai báo biến $ out cho đầu ra. Cảm ơn, Mike.
Mincong Huang

8

Vì vậy, nó là một vấn đề của mã hóa. Iconv giải quyết vấn đề

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

8

Bạn có thể làm điều này thay vì sử dụng -otùy chọn:

curl [url] > [file]


Vì vậy, không sử dụng đường ống và thay vào đó làm tất cả các công việc trên hệ thống tập tin? Tôi muốn sử dụng đầu ra của curl với đường ống.
tĩnh

6

Tôi đã có cùng một lỗi nhưng từ lý do khác nhau. Trong trường hợp của tôi, tôi có phân vùng (tmpfs) chỉ có 1GB dung lượng và tôi đang tải xuống tệp lớn cuối cùng đã lấp đầy tất cả bộ nhớ trên phân vùng đó và tôi cũng gặp lỗi tương tự như bạn.


5

Máy chủ đã hết dung lượng đĩa, trong trường hợp của tôi.

Kiểm tra nó với df -k .

Tôi đã được cảnh báo về việc thiếu không gian đĩa khi tôi thử đường ống qua tachai lần, như được mô tả trong một trong những câu trả lời khác: https://stackoverflow.com/a/28879552/336694 . Nó cho tôi thấy thông báo lỗi write error: No space left on device.


Tôi đã nhận được lỗi tương tự do hết dung lượng ổ đĩa trong một container, vì bất kỳ ai khác cũng gặp vấn đề tương tự có thể dọn sạch không gian trong các thùng chứa của họ vớidocker system prune
Dave

2

Tôi đã gặp thông báo lỗi này trong khi cố gắng cài đặt bộ nhớ cache véc ni trên Ubuntu. Tìm kiếm google đã đưa tôi đến đây vì lỗi (23) Failed writing body, do đó đăng một giải pháp hiệu quả với tôi.

Lỗi gặp phải trong khi chạy lệnh là root curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

giải pháp là chạy apt-key addnhư không root

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

1

Nếu bạn đang thử một cái gì đó tương tự như source <( curl -sS $url )và nhận được (23) Failed writing bodylỗi, đó là do tìm nguồn cung ứng thay thế quy trình không hoạt động bash 3.2(mặc định cho macOS).

Thay vào đó, bạn có thể sử dụng cách giải quyết này.

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

0

Đối với tôi, đó là vấn đề cho phép. Docker run được gọi với một hồ sơ người dùng nhưng root là người dùng bên trong container. Giải pháp là tạo curl write to / tmp vì điều đó có quyền ghi cho tất cả người dùng, không chỉ root.

Tôi đã sử dụng tùy chọn -o.

-o / tmp / file_to_d Download


-1

Trong Bash và zsh (và có lẽ các shell khác), bạn có thể sử dụng thay thế quy trình ( Bash / zsh ) để tạo tệp khi đang di chuyển, sau đó sử dụng tệp đó làm đầu vào cho quy trình tiếp theo trong chuỗi đường ống.

Ví dụ, tôi đã cố phân tích đầu ra JSON từ cURL bằng cách sử dụng jqless, nhưng đã nhận được Failed writing bodylỗi.

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

Khi tôi viết lại nó bằng cách sử dụng thay thế quá trình, nó đã làm việc!

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

Lưu ý: jqsử dụng đối số thứ 2 của nó để chỉ định tệp đầu vào

Bonus: Nếu bạn đang sử dụng jqnhư tôi và muốn giữ cho đầu ra colorized trong less, sử dụng dòng lệnh sau đây thay vì:

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

(Cảm ơn Kowaru vì đã giải thích lý do tại sao Failed writing body xảy ra. Tuy nhiên, giải pháp sử dụng tachai lần của họ không hiệu quả với tôi. Tôi cũng muốn tìm một giải pháp có thể mở rộng tốt hơn cho các tệp lớn và cố gắng tránh các vấn đề khác được ghi nhận là nhận xét với câu trả lời đó.)

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.