Почему выполнение простой команды в команде группировки не разветвляет процесс подоболочки, а составная команда сделает это

Я знаю, что группировка commands(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 должен разветвить процесс подоболочки, иначе он не сможет выполнить команду. Но почему я не вижу этого?


person Treasone    schedule 16.06.2019    source источник
comment
Используйте (echo $BASH_SUBSHELL) для вывода уровня подоболочки и используйте echo $BASHPID (bash ver › 4) для вывода идентификатора текущего процесса bash   -  person anubhava    schedule 16.06.2019
comment
К основам я рекомендую эту книгу: UNIX-среда   -  person Cyrus    schedule 16.06.2019
comment
Можете ли вы дать мне четкое объяснение, спасибо   -  person Treasone    schedule 16.06.2019
comment
Интересно, что вы также не видите процесс подоболочки bash при запуске (ps -f & cd). Это заставляет меня думать, что это может быть проблема времени.   -  person l0b0    schedule 16.06.2019
comment
Более минимальная демонстрация этого любопытства: ps -o ppid=$(pidof ps), затем с группировкой (ps -o ppid=$(pidof ps)), затем с группировкой и добавленной : командой бездействия (ps -o ppid=$(pidof ps) ; :). Первые два выводят одинаковые два числа, последний выводит те же два и еще одно.   -  person agc    schedule 16.06.2019
comment
Как сказали Камиль Чук и PSkocik, эти непредвиденные последствия могут быть вызваны оптимизацией bash.   -  person Treasone    schedule 16.06.2019


Ответы (2)


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. */
person KamilCuk    schedule 16.06.2019

Это похоже на оптимизацию, и dash, похоже, тоже это делает:

Бег

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

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

person PSkocik    schedule 16.06.2019