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

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

  • renice не работает в macOS Sierra
  • Доступ к функциям рыбы из perl
  • Печать stderr только в том случае, если в stdout ничего не записано, иначе распечатайте только stdout, отбрасывая stderr
  • Поддерживает ли bash поддержку, похожую на вилку C ()?
  • Diff stdin после прокладки его через команду
  • Правильное текстовое название для <<
  • начать процесс из ssh и иметь возможность закрыть соединение
  • Почему набрав «./» в 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

    Как оптимизировать время загрузки Arch linux?

    Окончания строк при использовании экрана GNU

    Можно просматривать файлы только через gvfs, а не открывать их

    Как добавить шаблон к заполнению bash (для распаковки)?

    Каков надежный способ получения каталога .ssh каждого пользователя из bash?

    Почему Bash не принимает `&> & 3`, т.е. перенаправляет stdout и stderr в дескриптор файла 3?

    Разбиение файла на две части на основе определенной строки

    Как рассказать графику Intel использовать мой пользовательский файл EDID?

    Kickstart – Конфигурация обоев

    Выполнять команду в переменной

    Наблюдение за записью жесткого диска в пространстве ядра (с драйверами / модулями)

    Пересылка каждого сообщения в папку на указанный адрес электронной почты

    Невозможно выполнить двоичный файл

    Не удается отправить почту в верхний домен

    «setcap» перезаписывает последнюю возможность. Как установить несколько возможностей?

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