Чому CURL повертає помилку "(23) Помилка запису"?


153

Це добре працює як єдиний інструмент:

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

1
проблемою було кодування сторінки (кирилиця, win-1251). Тому я повинен використовуватиiconv -f ...
статичний

5
Як і ще одна підказка: Моя не вдалася, оскільки диск був повний.
Вінс Варга

Відповіді:


113

Це відбувається, коли трубопровідна програма (наприклад, grep) закриває трубку для читання до того, як попередня програма закінчить написання всієї сторінки.

В curl "url" | grep -qs foo, як тільки Grep має те , що він хоче , щоб вона закриє для читання потоку з завитків. CURL цього не очікує і видає помилку "Не вдалося записати тіло".

Вирішення завдання полягає в передачі потоку через посередницьку програму, яка завжди зчитує всю сторінку, перш ніж подавати її наступній програмі.

Напр

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

tac- це проста програма Unix, яка зчитує всю сторінку введення та скасовує порядок рядків (отже, ми запускаємо її двічі). Оскільки він повинен прочитати весь вхід, щоб знайти останній рядок, він не видасть нічого, щоб вінче, поки CURL не буде завершено. Grep все одно закриє потік читання, коли він має те, що шукає, але це вплине лише на tac, який не видає помилки.


5
Не могли б ви просто пропустити це catодин раз? Принаймні, це вирішує для мене питання.
benvd

5
Ні. Це може допомогти з невеликими документами, але якщо вона занадто велика для розміщення в буфері кішка використовує помилку, знову з’явиться. Ви можете використовувати -sдля замовчування всіх повідомлень про помилки (і прогресу), якщо вони вам не потрібні.
Кавору

9
tac|tacзмінює вхід, якщо введення не закінчується подачею рядків, або, наприклад, printf a\\nb\\nc|tac|tacдрукує, a\ncbде \nпередається лінія. Ви можете використовувати sponge /dev/stdoutзамість цього. Інший варіант є printf %s\\n "$(cat)", але коли вхід містить нульові байти в оболонках, відмінних від Zsh, то або пропускає нульові байти, або зупиняє читання після першого нульового байта.
нісетама

З Документів: CURLE_WRITE_ERROR (23) Сталася помилка під час запису отриманих даних у локальний файл, або помилка була повернута libcurl із зворотного виклику запису. curl.haxx.se/libcurl/c/libcurl-errors.html
Джордан Стюарт

3
Цю відповідь слід прийняти, оскільки вона пояснює проблему, але, мабуть, вона не дає спроможного рішення, оскільки tacв macOS немає команди
Домінік Бючер

49

Для повноти та подальших пошуків:

Справа в тому, як 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я не отримую тієї ж помилки).
Дан Даскалеску

24

Інша можливість, якщо використовується -oопція (файл виводу) - каталог призначення не існує.

напр. якщо у вас є -o /tmp/download/abc.txtі / tmp / download не існує.

Отже, переконайтеся, що будь-які необхідні каталоги створені / існують заздалегідь, використовуйте --create-dirsпараметр, а також - oякщо необхідно


2
Спасибі!
rfay

1
Так само зі мною трапилось у подібному випадку. Я забув оголосити змінну $ out для виводу. Спасибі, Майку.
Мінконг Хуан

8

Тож це була проблема кодування. Іконів вирішує проблему

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]


Отже, не використовуючи трубу, а замість цього виконайте всю роботу над файловою системою? Я хотів використати вихід з завитками з трубами.
статичний

6

У мене була така ж помилка, але з іншої причини. У моєму випадку у мене був (tmpfs) розділ лише 1 Гб місця, і я завантажував великий файл, який нарешті заповнив усю пам'ять на цьому розділі, і я отримав ту ж помилку, що і ви.


5

У моєму випадку на сервері не вистачало місця на диску.

Перевірте це за допомогою df -k .

Мене попередили про відсутність дискового простору, коли я спробував прокручувати tacдвічі, як описано в одній з інших відповідей: https://stackoverflow.com/a/28879552/336694 . Він показав мені повідомлення про помилку write error: No space left on device.


Я отримав таку ж помилку через те, що у контейнері не вистачає місця на диску, тому що хтось, хто також потрапив у цю проблему, може очистити простір у своїх контейнерахdocker system prune
Дейв

2

Я зіткнувся з цим повідомленням про помилку під час спроби встановити кеш лаку на ubuntu. Пошук у Google висадив мене тут для помилки (23) Failed writing body, отже опублікував рішення, яке працювало на мене.

Помилка зустрічається під час виконання команди як root curl -L https://packagecloud.io/varnishcache/varnish5/gpgkey | apt-key add -

рішення полягає у запуску apt-key addяк некореневого

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 (і, можливо, інших оболонках) ви можете використовувати підстановку процесу ( Bash / zsh ) для створення файлу на льоту, а потім використовувати його як вхід до наступного процесу в ланцюзі конвеєра.

Наприклад, я намагався проаналізувати вихід JSON від cURL за допомогою jqта 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використовує свій 2-й аргумент для визначення вхідного файлу

Бонус: Якщо ви використовуєте , jqяк я і хочете , щоб тримати розфарбовані вихід в less, використовуйте наступну командний рядок замість того, щоб :

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

(Дякую Ковару за їх пояснення, чому Failed writing body це сталося. Однак, їхнє рішення використання tacдвічі для мене не спрацювало. Я також хотів знайти рішення, яке краще масштабуватиме для великих файлів, і намагається уникати інших проблем, зазначених як коментарі на цю відповідь.)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.