Я читаю о механизме fork & exec в Linux. Вот мои вопросы в теме.

  1. Означает ли это, что при вводе простой команды, такой как ls в командной строке процесс bash fork (дублирует себя), а затем выполняет вызов exec для замены клонированного кода bash кодом команды ls?
  2. Что касается приведенного выше примера и в соответствии с тем, что процесс doc: child process has the same environment as its parent процесс, означает ли это, что процесс команды ls будет иметь доступ ко всем переменным окружения, определенным до сих пор в bash?
  3. Применяется ли механизм только к двоичным файлам, таким как встроенные команды или к сценариям оболочки?

2 ответа2

1
  1. Нет, он порождает /usr/bin/ls как дочерний процесс. Вы можете поиграть со strace если вас интересуют такие вещи:

    [foo@turtle ~]$ strace -f -eexecve -o bash.strace bash
    [foo@turtle ~]$ ls
    bash.strace
    [foo@turtle ~]$ exit
    [foo@turtle ~]$ cat bash.strace 
    26213 execve("/usr/bin/bash", ["bash"], [/* 37 vars */]) = 0
    26214 +++ exited with 0 +++
    26213 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26214, si_uid=10003, si_status=0, si_utime=0, si_stime=0} ---
    26230 execve("/usr/bin/ls", ["ls", "--color=auto"], [/* 37 vars */]) = 0
    26230 +++ exited with 0 +++
    26213 --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=26230, si_uid=10003, si_status=0, si_utime=0, si_stime=0} ---
    26213 +++ exited with 0 +++
    
  2. Да, это вроде как: есть разница, экспортируется ли она или нет:

    [foo@turtle ~]$ DIR_I_WANT_TO_LS=/home/foo 
    [foo@turtle ~]$ ls $DIR_I_WANT_TO_LS
    bar  bash.strace  ls_from_a_script.sh
    [foo@turtle ~]$ set -x
    [foo@turtle ~]$ ls $DIR_I_WANT_TO_LS
    bar  bash.strace  ls_from_a_script.sh
    [foo@turtle ~]$ ./ls_from_a_script.sh 
    $DIR_I_WANT_TO_LS=
    bar  bash.strace  ls_from_a_script.sh
    $DIR_I_WANT_TO_LS=/home/foo/bar
    [foo@turtle ~]$ export DIR_I_WANT_TO_LS
    [foo@turtle ~]$ ./ls_from_a_script.sh 
    $DIR_I_WANT_TO_LS=/home/foo
    bar  bash.strace  ls_from_a_script.sh
    $DIR_I_WANT_TO_LS=/home/foo/bar
    
  3. Нет, он отлично работает с любой программой (бинарная, shell, ruby, python, lua, node ...). Последние обычно имеют структуру, часто называемую ENV для этого.

0

Означает ли это, что при вводе простой команды, такой как ls, в командной строке процесс bash разветвляется (дублирует себя), а затем выполняет вызов exec для замены клонированного кода bash кодом команды ls?

В основном да. Хотя технические детали могут отличаться:

  • В современных ОС fork() работает быстро благодаря копированию при записи. Но в некоторых старых системах каждая ветвь должна была создавать полную копию памяти процесса, поэтому оболочки вместо этого использовали vfork(2), который только создавал новый процесс, но разделял ту же память.

  • (В Linux функция fork(3) в libc фактически использует системный вызов clone(2) . Конечный результат все тот же, хотя.)

  • В libc есть различные функции exec… (3) , которые все переводятся в системный вызов execve (2) .

Что касается приведенного выше примера и в соответствии с тем, что процесс doc: child имеет ту же среду, что и его родительский процесс, означает ли это, что процесс команды ls будет иметь доступ ко всем переменным окружения, определенным до сих пор в bash?

Это будет иметь доступ к копии этих переменных среды. (Так что, если бы ls сделал какие-либо изменения, они бы не пошли вверх.)

Обратите внимание, что не все переменные bash автоматически являются переменными среды - только те, которые явно «экспортированы» в среду. (Вы можете использовать declare -p чтобы увидеть все переменные, экспортированные или нет.)

Применяется ли механизм только к двоичным файлам, таким как встроенные команды или к сценариям оболочки?

Это также относится к сценариям оболочки - ядро рассматривает сценарии с #! быть исполняемым и передает их любому "интерпретатору", указанному в #! линия.

(В Linux также есть "binfmt_misc", который позволяет определять и исполнять пользовательские форматы - например, он может быть выполнен для запуска .exe через Wine.)

Хотя если ядро отклоняет вызов exec, некоторые оболочки все равно будут пытаться запустить сценарий вручную, выполняя /bin /sh с этим сценарием. (На самом деле, иногда это даже делает libc - есть упоминание в man-странице glibc exec(3) .)

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .