Почему выполнение простой команды в группирующей команде не является ветвью процесса подоболочки, и составная команда сделает это - PullRequest
3 голосов
/ 16 июня 2019

Я знаю, что группирование команд (command-list) создает среду подоболочки , и каждая перечисленная команда выполняется в этой подоболочке .Но если я выполню простую команду в команде группировки (используйте команду ps для вывода процессов), то никакой процесс подоболочки не выводится .Но если я попытался выполнить список команд ( составная команда ) в команде группировки, то процесс подоболочки будет выведен .Почему он дает такой результат?

  • Тест выполнения простой команды (только команда ps) в команде группировки:
    [root@localhost ~]# (ps -f)
    
    со следующим выводом:
    UID         PID   PPID  C STIME TTY          TIME CMD
    root       1625   1623  0 13:49 pts/0    00:00:00 -bash
    root       1670   1625  0 15:05 pts/0    00:00:00 ps -f
    
  • Еще один тест выполнения составной команды (список команд) в команде группировки:
    [root@localhost ~]# (ps -f;cd)
    
    со следующим выводом:
    UID         PID   PPID  C STIME TTY          TIME CMD
    root       1625   1623  0 13:49 pts/0    00:00:00 -bash
    root       1671   1625  0 15:05 pts/0    00:00:00 -bash
    root       1672   1671  0 15:05 pts/0    00:00:00 ps -f
    

Я протестировал множество других команд (составные команды и простые команды), но результаты совпадают.Я предполагаю, что даже если я выполню простую команду в команде группировки, bash должен обработать процесс подоболочки, иначе он не сможет выполнить команду.Но почему я не вижу этого?

Ответы [ 2 ]

4 голосов
/ 16 июня 2019

Bash оптимизирует выполнение. Он обнаруживает, что в группу ( ) входит только одна команда, и вызывает fork + exec вместо fork + fork + exec. Вот почему в списке процессов вы видите один bash процесс меньше. Это легче обнаружить при использовании команды, которая занимает больше времени ( sleep 5 ) для устранения хронометража. Также вы можете прочитать эту ветку в unix.stackexchange.

Я думаю, что оптимизация выполняется где-то внутри execute_cmd.c в execute_in_subshell() функции (добавлены мной стрелки >):

 /* If this is a simple command, tell execute_disk_command that it
     might be able to get away without forking and simply exec.
>>>> This means things like ( sleep 10 ) will only cause one fork
     If we're timing the command or inverting its return value, however,
     we cannot do this optimization. */

и в функции execute_disk_command() мы также можем прочитать:

/* If we can get away without forking and there are no pipes to deal with,
   don't bother to fork, just directly exec the command. */
2 голосов
/ 16 июня 2019

Похоже, что оптимизация, и, похоже, это делает и черта:

Запуск

bash -c '( sleep 3)' & sleep 0.2 && ps #or with dash

как и более надежно:

strace -f -e trace=clone dash -c '(/bin/sleep)' 2>&1 |grep clone # 1 clone

показывает, что подоболочка пропущена, но если после дочернего процесса в подоболочке необходимо выполнить последующую работу, то подоболочка создается:

strace -f -e trace=clone dash -c '(/bin/sleep; echo done)' 2>&1 |grep clone #2 clones

Zsh и ksh делают еще один шаг вперед и (когда они видят, что это последняя команда в скрипте):

strace -f -e trace=clone ksh -c '(/bin/sleep; echo done)' 2>&1 |grep clone # 0 clones

они вообще не форкаются (= клонируются), исключая непосредственно в процессе оболочки.

...