Неинтерактивные оболочки просто не имеют источника .bashrc
; это определенное поведение bash
. Неинтерактивная оболочка будет источником только файла с именем переменной среды BASH_ENV
. (Если запустить как sh
, то вместо имени файла в качестве источника используется ENV
.)
На странице руководства (выделено мной жирным шрифтом)
Когда bash вызывается как интерактивная оболочка входа в систему или как не- активная оболочка с оператором - -login сначала считывает и выполняет команды com - {1}} из файла / etc / profile , если этот файл существует. После чтения этого файла он ищет ~ / .bash_profile, ~ / .bash_login и ~ / .profile, в указанном порядке, а также читает и выполняет команды из первого файла. , что существует и доступен для чтения. Параметр --noprofile может использоваться при запуске оболочки , чтобы запретить такое поведение.
Когда оболочка входа завершается, bash читает и выполняет команды из файла ~ / .bash_logout, если он существует.
Когда запускается интерактивная оболочка , которая не является оболочкой входа в систему , bash читает и выполняет команды из ~ / .bashrc , если этот файл существует. Это можно запретить с помощью параметра --norc. Параметр файла --rcfile заставит bash читать и выполнять команды из файла вместо ~ / .bashrc.
Когда bash запускается в неинтерактивном режиме , чтобы запустить сценарий оболочки, например , он ищет переменную BASH_ENV в среде, расширяет ее значение, если он появляется там и использует расширенное значение как имя файла для чтения и выполнения. Bash ведет себя так, как если бы был выполнен следующий com - {1}} mand: if [-n "$ BASH_ENV"]; тогда . "$ BASH_ENV"; fi , но значение переменной PATH не используется для поиска файла - имя.
В:
cmd1 | cmd2
cmd2
не умирает автоматически, когда cmd1
завершает работу, однако он увидит конец -файла -на своем стандартном вводе. И вот так трубопроводы обычно заканчиваются.
В:
echo foo | sed s/o/e/g
sed
прекратит работу после того, как echo
завершится, потому что он обнаружит, что больше нечего читать из его стандартного ввода.
Вы можете попытаться cmd1
убить cmd2
после завершения, но что, если cmd2
еще не прочитал все, что cmd1
написал в канал?
Если cmd2
умирает первым, cmd1
не умирает автоматически, но он будет уничтожен (с помощью SIGPIPE )при следующей попытке записи в (теперь сломанный )канал.
Вот такие конвейеры:
yes | head
terminate(yes
уничтожается при первой записи в канал после завершения head
после чтения и печати первых 10 строк ).
Теперь, если вы действительно хотите убить процессы на другом конце канала, нет переносимого способа узнать, какой процесс (es )имеет файловый дескриптор на другом конце канала.
В Linux вы можете искать файлы в /proc/*/fd
, которые имеют тот же индекс, что и канал на fd до вашего конца канала, и где разрешения самой символической ссылки указывают, какой конец канала это.
$ (ls -lLi /proc/self/fd/3; ls -l /proc/self/fd/3) 3>&1 >&2 | (ls -Lil /proc/self/fd/0; ls -l /proc/self/fd/0)
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/3|
224052 prw------- 1 chazelas chazelas 0 Sep 20 23:26 /proc/self/fd/0|
l-wx------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/3 -> pipe:[224052]
lr-x------ 1 chazelas chazelas 64 Sep 20 23:26 /proc/self/fd/0 -> pipe:[224052]
Один и тот же индекс канала, и fd на стороне записи имеет разрешения w
, а на стороне чтения — права r
.
Например,с помощью zsh
вы можете получить pid процессов, у которых есть fd на считывающем конце канала, другой конец которого находится на нашем fd 3 с помощью:
pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}) # unique
Пример:
$ (pids=(/proc/<->/fd/*(Nf{u+r}e{'[[ $REPLY -ef /dev/fd/3 ]]'}-p:h:h:t))
pids=(${(u)pids}); ps -fp $pids) 3>&1 >&2 | tr a b
UID PID PPID C STIME TTY TIME CMD
chazelas 24157 11759 0 23:41 pts/1 00:00:00 tr a b
Так что вы могли бы сделать (по-прежнему в Linux и сzsh
):
run_and_kill_the_other_end() {
setopt localoptions localtraps
trap : TERM
"$@"
local ret=$?
local -aU pids
if [ -p /dev/stdout ]; then
pids=(/proc/<2->/fd/<0-9>(Nf{u+r}e{'[[ $REPLY -ef /dev/stdout ]]'}-p:h:h:t))
exec >&- # give the right end a chance to see eof and act upon it
fi
[ -p /dev/stdin ] &&
pids+=(/proc/<2->/fd/<0-9>(Nf{u+w}e{'[[ $REPLY -ef /dev/stdin ]]'}-p:h:h:t))
(($#pids)) && kill $pids 2> /dev/null
return $ret
}
А потом:
run_and_kill_the_other_end node a.js | run_and_kill_the_other_end node b.js
Хотя опять же, это, вероятно, не то, что вы хотите делать. Например:
$ run_and_kill_the_other_end seq 100 |
run_and_kill_the_other_end sort |
run_and_kill_the_other_end wc -l
0
sort
был убит до того, как успел записать свой отсортированный вывод. wc -l
удалось бежать.
В качестве льготного периода можно указать задержку, но какой продолжительности она должна быть? Например, если я добавлю sleep 0.1
после exec >&-
, я увижу:
$ run_and_kill_the_other_end seq 100 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
100
$ run_and_kill_the_other_end seq 10000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
10000
$ run_and_kill_the_other_end seq 100000 | run_and_kill_the_other_end sort | run_and_kill_the_other_end wc -l
0
Это также означает безоговорочную отсрочку закрытия конвейера. Вы можете улучшить это, используя вместо этого zsh
zselect
с тайм-аутом.