2015-10-02 4 views
7

У меня есть Баш скрипт: my.shПочему мой сценарий блокировки bash?

#!/bin/bash 

do_sth() 
{ 
    sleep 5 
} 

main() 
{ 
    do_sth >/dev/null & 
    echo do sth in background ... 
} 

if [ "$1" = "1st_way" ]; then 
    main 
elif [ "$1" = "2nd_way" ]; then 
    main >/dev/null 
fi 

Следующая команда возвращает немедленно

./my.sh 1st_way | cat 

Но, следующая команда блоков в течение 5 секунд

./my.sh 2nd_way | cat 

Интересно, почему он блокирует в течение 5 секунд на втором пути.

ответ

5

Рассмотрим этот скрипт:

#!/bin/bash 

main() { 
    cd /tmp 
} 

main > /dev/null 
echo goodbye 

Перед Баш запускает функцию main, он должен перенаправить свой собственный стандартный вывод /dev/null. Затем необходимо запустить функцию main. Затем перед выполнением команды echo необходимо восстановить свой стандартный вывод до того, что было до перенаправления.

Вот как это делается. Чтобы сделать перенаправление, он открывает /dev/null, получив (скажем) файловый дескриптор 3. Затем он дублирует свой файловый дескриптор 1 (стандартный вывод) на первый доступный fd ≥ 10, получая (допустим) 10. Затем он дублирует fd 3 (открыть на /dev/null) до Fd 1, и закрывает FD 3.

Позже, чтобы отменить переадресацию, он дублирует FD 10 (открытую на оригинальном стандартном выводе в Bash) на дескриптор 1, и закрывает Fd 10.

Хорошо , теперь вернемся к вашему сценарию. Все то же происходит, когда ваш скрипт говорит main >/dev/null, поэтому, пока выполняется main, fd 10 открыт на исходном стандартном выходе оболочки, который является записываемым концом трубы до cat.

Когда ваш main говорит do_sth >/dev/null &, раковина вилки. Дочерняя оболочка наследует fd 10, поэтому как родительская, так и дочерняя оболочки имеют fd 10, открытых на трубе. (Обратите внимание, что оболочка знает, что ему не нужно, чтобы сохранить свой стандартный вывод здесь из-за & делает его вилкой.)

Когда ребенок оболочки, в do_sth, работает sleep, он ветвится запустить sleep и ждет sleep для выхода. Таким образом, дочерняя оболочка висит вокруг в течение пяти секунд, и за это время она открывает fd 10 на записываемом конце трубы.

cat процесс не читает EOF на читаемом конце трубы, пока все дескрипторы файлов на записываемый конце закрыты, что не происходит до тех пор, что выходит ребенок оболочки, который не происходит до тех пор, sleep выходов.

Смежные вопросы