$ ls -l test1 ; cat test1
-rwxr-xr-x 1 arnold devel 93 Oct 20 22:11 test1
#! /bin/sh
read line ; echo p: $line /* Прочесть строку в родительской оболочке,
вывести ее */
( read line ; echo с: $line ) /* Прочесть строку в порожденной оболочке,
вывести ее */
read line ; echo p: $line /* Прочесть строку в родительской оболочке,
вывести ее */
$ test1 < data
p: line 1 /* Родитель начинает сначала */
c: line 2 /* Порожденный продолжает оттуда, где остановился родитель */
p: line 3 /* Родитель продолжает оттуда, где остановился порожденный */
Первая исполняемая строка test1
test1 запускает команды, заключенные между скобками, в подоболочке (subshell). Это отдельный процесс оболочки, созданный — как вы догадались — с помощью fork(). Порожденная подоболочка наследует от родителя стандартный ввод, включая текущее смещение. Этот процесс читает строку и обновляет разделяемое смещение в файле. Когда третья строка, снова в родительской оболочке, читает файл, она начинает там, где остановился порожденный.Хотя команда read
line, которая читала одну строку ввода (по одному символу за раз!) для использования в сценариях оболочки; если бы смещение файла не было разделяемым, было бы невозможно использовать такую команду в цикле.Разделение дескрипторов файлов и наследование играют центральную роль в перенаправлении ввода/вывода оболочки; системные вызовы и их семантика делают примитивы уровня оболочки простыми для реализации на С, как мы позже увидим в данной главе.
9.1.1.3. Разделение дескрипторов файлов и close()
Тот факт, что несколько дескрипторов файлов могут указывать на один и тот же открытый файл, имеет важное следствие:
Позже в главе мы увидим, что несколько дескрипторов для одного файла могут существовать не только для разных процессов, но даже и внутри одного и того же процесса; это правило особенно важно для работы с каналами (pipes).
Если вам нужно узнать, открыты ли два дескриптора для одного и того же файла, можете использовать fstat()
struct stat. Если соответствующие поля st_dev и st_ino равны, это один и тот же файл.Позже в главе мы завершим обсуждение манипуляций с дескрипторами файлов и таблицей дескрипторов файлов.
9.1.2. Идентификация процесса: getpid()
getppid()У каждого процесса есть уникальный ID номер процесса (PID). Два системных вызова предоставляют текущий PID и PID родительского процесса:
#include
#include
pid_t getpid(void);
pid_t getppid(void);
Функции так просты, как выглядят:
pid_t getpid(void)
pid_t getppid(void)
Значения PID уникальны; по определению, не может быть двух запущенных процессов с одним и тем же PID. PID обычно возрастают в значении, так что порожденный процесс имеет обычно больший PID, чем его родитель. Однако, на многих системах значения PID
Если родительский процесс завершается, порожденный получает нового родителя, init
init. Такой порожденный процесс называется ch09-reparent.с, демонстрирует это. Это также первый пример fork() в действии:1 /* ch09-reparent.c --- показывает, что getppid() может менять значения */
2
3 #include
4 #include
5 #include
6 #include
7