ошибка обрыва трубы с помощью 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') 

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

  • Поддерживает ли bash поддержку, похожую на вилку C ()?
  • Как перенести вывод из одного процесса в другой, но только выполнить, если первый имеет выход?
  • Запуск команды источника с -x для отладки
  • Как сделать двунаправленную трубку между двумя программами?
  • Начать несколько рыбных снарядов в разных каталогах?
  • Доступ к функциям рыбы из perl
  • Команда источника подачи с трубой
  • Почему набрав «./» в sh произведите «разрешение отказа»?
  • 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", ...) 
    Interesting Posts

    Размещение окна при переключении на несколько мониторов

    Bash не полностью функциональен для нового пользователя

    Msgstr "ошибка установки gummiboot-efi" на установке Archboot UEFI

    Итерация повторяющегося токового цикла, если выполняется какое-либо условие (bash)

    Как изменить линию консоли консоли Linux (на некоторое время)

    Режим GNU Emacs Prolog

    OpenSuse – сетевые проблемы

    Atom 230 + 2GB RAM хранилище данных для небольшого сервера = 64-разрядный или 32-разрядный debian

    Может ли bash развернуть цитированную и / или экранированную строковую переменную в слова?

    Как переименовать несколько файлов с префиксом и суффиксом с помощью команды find

    Как копировать или перемещать файлы без запроса на перезапись?

    HOWTO обнаруживает, когда JBOSS полностью запущен и готов принять развертывание?

    Отключить сортировку COMPREPLY в полной функции bash

    большие серверы электронной почты, отправляемые с сервера, не могут идентифицировать

    Как сделать svn искать, если есть обновление раз в минуту, и если есть вызов какого-то скрипта?

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