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

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

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

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

  • Git совершает использование stdout из bash?
  • В чем же разница между трубами и потоками?
  • tar: параметр требует аргумента - 'f'
  • перенаправление на проблемы с файлом nohup и pipe
  • У одного конца трубы есть как чтение, так и запись fd?
  • Почему эти значения не добавляются правильно при добавлении к конвейеру?
  • Печать текущего количества байтов в трубе
  • Почему я не могу аутентифицировать запрос на завивание, когда трубопровод меньше или больше?
  • 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" надеясь, что достаточно, чтобы команда прочитала содержимое, оставшееся в трубке, и сделало то, что ему нужно для этого.

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