ошибка обрыва трубы с помощью popen и JS ffi

Я использую ffi для nodejs, который по большей части не имеет ничего общего с этим вопросом, который действительно лучше понимает каналы, но предлагает некоторый контекст

function exec(cmd) { var buffer = new Buffer(32); var result = ''; var fp = libc.popen('( ' + cmd + ') 2>&1', 'r'); var code; if (!fp) throw new Error('execSync error: '+cmd); while( !libc.feof(fp) ){ libc.fgets(buffer, 32, fp) result += buffer.readCString(); } code = libc.pclose(fp) >> 8; return { stdout: result, code: code }; } 

который приводит меня к этому биту кода, который, когда я запускаю эту функцию exec

  tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8} 

Я получаю ошибку

 write error: Broken pipe tr: write error 

но я получаю результат. Я ожидаю 8 случайных чисел, это сбило меня с ума, но потом в каком-то диком поиске я нашел ответ на этот стек, который идеально подходит для моей ситуации.

Я остаюсь с этими вопросами, хотя …

Почему

 tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8} 

сбросить ошибку разбитого трубопровода при вызове с моей командой exec, но не при вызове из оболочки. Я не понимаю, почему, когда я звоню

 tr -dc "[:alpha:]" < /dev/urandom 

он читает бесконечно, но когда я его

 head -c ${1-8} 

Он работает с выкидыванием неисправной ошибки трубы. Кажется, что глава возьмет то, что ему нужно, и тр будет просто читать навсегда. По крайней мере, он должен бросить сломанную трубу, голова будет потреблять первые 8 байтов, а затем tr все равно будет выставлять выход, а сломанная труба будет выбрана tr, потому что голова перестала работать.

Обе ситуации имеют смысл для меня, но кажется, что они являются чем-то исключительным для друг друга. Я не понимаю, что между вызовами

 exec(tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8}) 

а также

 tr -dc "[:alpha:]" < /dev/urandom | head -c ${1-8} 

непосредственно из командной строки

и особенно почему <бесконечный файл во что-то, а затем | это что-то заставляет его не бежать бесконечно, я делал это много лет и никогда не сомневался, почему он работает таким образом.

Наконец, нормально ли игнорировать эту неисправную трубку? Есть ли способ исправить это я делаю что-то не так в моем javascript-коде c ++. Я пропустил какие-то основы всплывающих окон?

—— РЕДАКТИРОВАТЬ

еще немного испортить код

 exec('head -10 /dev/urandom | tr -dc "[:alpha:]" | head -c 8') 

не выводит трубную ошибку!

One Solution collect form web for “ошибка обрыва трубы с помощью popen и JS ffi”

Обычно tr не должен писать это сообщение об ошибке, потому что он должен был быть убит сигналом SIGPIPE при попытке написать что-либо после того, как другой конец трубы был закрыт по завершении head .

Вы получаете это сообщение об ошибке, потому что каким-то образом процесс, выполняющий tr , настроен на игнорирование SIGPIPE. Я подозреваю, что это может быть сделано с помощью функции popen() на вашем языке.

Вы можете воспроизвести его, выполнив:

 sh -c 'trap "" PIPE; tr -dc "[:alpha:]" < /dev/urandom | head -c 8' 

Вы можете подтвердить, что это происходит:

 strace -fe signal sh your-program 

(или эквивалент вашей системы, если не используете Linux). Затем вы увидите что-то вроде:

 rt_sigaction(SIGPIPE, {SIG_IGN, ~[RTMIN RT_1], SA_RESTORER, 0x37cfc324f0}, NULL, 8) = 0 

или

 signal(SIGPIPE, SIG_IGN) 

выполняется в одном процессе до того же процесса или один из его потомков выполняет /bin/sh который интерпретирует эту командную строку и запускает tr и head .

Если вы сделаете запись strace -fe write , вы увидите что-то вроде:

 write(1, "AJiYTlFFjjVIzkhCAhccuZddwcydwIIw"..., 4096) = -1 EPIPE (Broken pipe) 

Системный вызов записи не выполняется с ошибкой EPIPE вместо запуска SIGPIPE.

В любом случае tr выйдет. При игнорировании SIGPIPE из-за этой ошибки (но это также вызывает сообщение об ошибке). Когда нет, он выходит после получения SIGPIPE. Вы хотите, чтобы он вышел, поскольку вы не хотите, чтобы он продолжал чтение /dev/urandom после того, как эти 8 байтов были read head .

Чтобы избежать этого сообщения об ошибке, вы можете восстановить обработчик по умолчанию для SIGPIPE с помощью:

 trap - PIPE 

Перед вызовом tr :

 popen("trap - PIPE; { tr ... | head -c 8; } 2>&1", ...) 
  • Как сделать двунаправленную трубку между двумя программами?
  • Как вы выводите список всех справочных страниц в определенном разделе?
  • Команды соединения в unix
  • Есть ли у рыбы «магическое пространство»?
  • Получите обновляющий список запущенных определенных процессов
  • Что такое переносимый (POSIX) способ достижения замещения процесса?
  • начать процесс из ssh и иметь возможность закрыть соединение
  • renice не работает в macOS Sierra
  • Как вы организуете свой ДОМЕН?
  • Могу ли я использовать modulecmd с раковиной?
  • bourne shell, если
  • Interesting Posts

    Один ПК, несколько пользователей, Gnome 3 и Awesome. Как легко переключаться между пользователями через GDM

    Как загрузить загрузочный носитель Fedora 17 для загрузки моего ноутбука?

    Может ли 32-разрядные приложения на 64-битном ядре использовать всю память?

    Могу ли я поделиться локальным хостом с другими пользователями моей Linux-коробки?

    Как загрузить модуль виртуального ядра видео ядра?

    Как отобразить имя дистрибутива (только) из lsb_release -i

    Как заставить Kali Linux не заснуть?

    Какой системный файл загружает модуль ядра wli (wifi) во время загрузки?

    Файловая система, которая разбивает большие файлы

    Мост / Совместное использование сетевого принтера в freebsd

    Как отправить ввод в программу на C с помощью сценария оболочки

    Где находится файл rc для редактора vi.

    Rsync, включают только определенные типы файлов, исключая некоторые каталоги

    Команда для удаления первого N числа строк на входе

    Конфигурация шлюза не работает

    Linux и Unix - лучшая ОС в мире.