Процесс не закрывается при закрытии stdin

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

Я закончил программу, затем перешел к proc / pid / fd для процесса и обнаружил, что его stdin все еще связан с / dev / pts / 2.

Почему в этом случае процесс не будет закрыт? Еще лучше, есть ли оболочка или техника, которые я могу использовать, чтобы гарантировать, что программа закроется, когда ее труба stdin закрывается?

  • Шифрование импорта импорта с помощью gpg в одно и то же время
  • Что такое переносимый (POSIX) способ достижения замещения процесса?
  • less: переход к концу как можно большего количества буфера, а не фактического конца буфера
  • Загрузите файл и канал в несколько команд
  • Не могли бы вы объяснить, почему эта команда (pgrep -d ',' -f cmdStr | top -c -p) не работает?
  • Как перенаправить stdout и stdin в telnet?
  • Bash: не может вырваться из цикла «while read»; технологические замещения
  • Прочитайте до закрытия трубы
  • One Solution collect form web for “Процесс не закрывается при закрытии stdin”

    stdin – это дескриптор файла 0 . Закрытие файлового дескриптора процесса – это то, что может быть сделано только самим процессом. stdin закрывается, когда процесс решает закрыть его.

    Теперь, когда stdin процесса является считывающим концом трубы, другой конец трубы может быть открыт одним или несколькими другими процессами. Когда все дескрипторы файлов на другом конце закрыты, чтение из этого канала будет считывать оставшиеся данные в этом канале, но в итоге ничего не вернет (вместо ожидания большего количества данных), что означает конец файла.

    Приложения, такие как cat , cut , wc …, которые читают со своего stdin, обычно выходят, когда это происходит, потому что их роль заключается в обработке их ввода до конца, пока нет больше ввода.

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

    В:

     echo foo | cat 

    После того, как echo написал "foo\n" , он завершает работу, из-за чего конец записи будет закрыт, затем read() выполненный cat на другом конце, возвращает 0 байтов, в котором говорится, что больше ничего не читать, а затем cat решает выйти.

    В

     echo foo | sleep 1 

    sleep только выход через 1 секунду. Его stdin, становясь закрытой трубой, не имеет никакого отношения к этому, sleep даже не читает со своего stdin.

    На пишущих концах труб (или сокетов для этого важно другое дело).

    Когда все fds на считывающем конце были закрыты, любая попытка записи на fds, открытая для конца записи, заставляет SIGPIPE посылаться процессу, заставляя его умереть (если он не игнорирует сигнал, в этом случае write() с EPIPE ).

    Но это происходит только тогда, когда они пытаются писать.

    Например, в:

     sleep 1 | true 

    Несмотря на то, что true выход сразу, а конец чтения затем закрывается сразу, sleep не убивается, потому что он не пытается писать на его выступление.


    Теперь о /proc/fd/pid/n отображаемом красным цветом в выводе ls -l --color (как упоминалось в первой версии вашего вопроса ), это только потому, что ls делает lstat() в результате readlink() на этой символической ссылке, чтобы попытаться определить тип цели ссылки.

    Для дескрипторов файлов, открытых в трубах, или сокетах или файлах в других пространствах имен или удаленных файлах, результат readlink не будет фактическим путем в файловой системе, поэтому второй lstat() выполняемый ls , потерпит неудачу, и я подумаю, что это сломанная символическая ссылка, а сломанные символические ссылки отображаются красным цветом. Вы получите это с любым fd на любой конец любой трубы, независимо от того, закрыт ли другой конец трубы или нет. Попробуйте с ls --color=always -l /proc/self/fd | cat например, ls --color=always -l /proc/self/fd | cat .

    Чтобы определить, указывает ли fd на сломанный канал, в Linux вы можете попробовать lsof с параметром -E .

     $ exec 3> >(:) 4> >(sleep 999) $ lsof -ad3-4 -Ep "$$" COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME zsh 13155 stephane 3w FIFO 0,10 0t0 5322414 pipe zsh 13155 stephane 4w FIFO 0,10 0t0 5323312 pipe 392,sleep,0r 

    Для fd 3 lsof не смог найти какой-либо другой процесс на считывающем конце трубы. Остерегайтесь, однако, что вы можете получить вывод, например:

     $ exec 5<&3 $ lsof -ad3-5 -Ep "$$" COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME zsh 13155 stephane 3w FIFO 0,10 0t0 5322414 pipe 13155,zsh,5w zsh 13155 stephane 4w FIFO 0,10 0t0 5323312 pipe 392,sleep,0r zsh 13155 stephane 5w FIFO 0,10 0t0 5322414 pipe 392,sleep,3w 13155,zsh,3w 

    fds 3 и 5 по-прежнему повреждены, потому что нет fd для конца чтения (кажется, есть ошибка в lsof, поскольку тот факт, что sleep также имеет свой fd 3, открытый для сломанной трубы, не отражается повсюду).


    Чтобы убить процесс, как только труба, открытая на своем stdin, теряет свой последний писатель (становится сломанным), вы можете сделать что-то вроде:

     run_under_watch() { perl -MIO::Poll -e ' if ($pid = fork) { $SIG{CHLD} = sub { wait; exit($? & 127 ? ($? & 127) + 128 : $? >> 8); }; $p = IO::Poll->new; $p->mask(STDIN, POLLERR); $p->poll; kill "TERM", $pid; sleep 1; kill "KILL", $pid; exit(1); } else { exec @ARGV }' "$@" } 

    Который будет следить за условием ошибки на stdin (и на Linux, похоже, что это произойдет, как только не осталось ни одного автора, даже если в трубе остались данные) и как только это произойдет, убейте дочернюю команду. Например:

      sleep 1 | run_under_watch sleep 2 

    Убьет процесс sleep 2 через 1 секунду.

    Теперь, как правило, это немного глупо. Это означает, что вы потенциально убиваете команду, прежде чем она успеет обработать конец ввода. Например, в:

      echo test | run_under_watch cat 

    Вы обнаружите, что cat иногда убивают, прежде чем она успеет вывести (или даже прочитать!) "test\n" . Нет никакого способа обойти это, наш наблюдатель не может знать, сколько времени команда должна обрабатывать входные данные. Все, что мы можем сделать, это дать льготный период перед kill "TERM" надеясь, что достаточно, чтобы команда прочитала содержимое, оставшееся в трубке, и сделало то, что ему нужно для этого.

    Interesting Posts

    Проблема Yum на Centos 6.7

    Замените экземпляры слов своим прикрепленным к нему числом

    «Ifconfig -a» не показывает никаких интерфейсов

    Сканировать хотя каталог файлов и найти реплики с тем же именем и объединить их в один файл

    Как сценарировать миграцию базы данных с помощью SSH?

    Nullpointer разыгрывает разрывы при больших выделениях памяти на ESXi с пользователями Linux

    Ошибка Mint 13, которая предотвращает щелчок правой кнопкой мыши на значках рабочего стола и множество других симптомов

    Использование pmap и памяти

    Отладка функций bash

    Можно ли перенаправить системные звуковые сигналы на обычный звук?

    Создание загрузочного GPT-раздела EFI с помощью gdisk на предыдущем MBR, поврежденный GPT

    Что делает ядро ​​Linux с неизвестными параметрами ядра?

    Отключение затенения окна мыши в XFce?

    Замените несколько пробелов одним, используя только «tr»

    apt-get удалить php5 без установки apache2

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