Есть ли подоболочка, созданная при запуске команды "sh -c" "новая оболочка или ни одна из них?

В bash, когда я запускаю следующую команду:

sh -c "command"

создается подоболочка, а затем выполняется command?

Я предполагаю, что команда будет запущена в текущей оболочке, но я не уверен. Это связано с тем, что я уже тестировал, используя следующие команды:

echo $BASHPID, $BASH_SUBSHELL

и

sh -c "echo $BASHPID, $BASH_SUBSHELL"

и результаты те же. Но это может немного ввести в заблуждение, поскольку кто-то сказал мне, потому что переменные могут быть заменены до выполнения команды. Это правда?

Ответ 1

Я думаю, что с примерами можно понять ситуацию (в моем случае sh является символической ссылкой на /bin/dash).
Я сделал эти тесты для sh:

echo $$ ; sh -c 'echo $$ ; sh -c '"'"'echo $$'"'"' '
16102
7569
7570

Три разных PID, три разных shell. (Если есть разные оболочки, не существует икры подповерхности).


Аналогично для BASH

echo $$ $BASHPID, $BASH_SUBSHELL ; bash -c 'echo $$  $BASHPID $BASH_SUBSHELL  ; bash -c '"'"'echo  $$ $BASHPID $BASH_SUBSHELL '"'"' '
16102 16102, 0
10337 10337 0
10338 10338 0

Три разных $BASHPID не разные $BASH_SUBSHELL (см. примечание ниже для различий между $$ и $BASHPID).
Если бы мы были в подоболочке, которая не требует повторной инициализации, то $$ и $BASHPID должны быть разными.
Точно так же $BASH_SUBSHELL не увеличивается, он всегда 0. Итак, 2 подсказки, чтобы снова сказать, что новая подоболочка не порождена, у нас есть только новые оболочки.


Из man bash (4.2.45 (1) -release) Сообщаю о некоторых соответствующих деталях о , когда порождается подоболочка:

  • Каждая команда в конвейере выполняется как отдельный процесс (т.е. в подоболочке).

  • Если команда завершена оператором управления &, оболочка выполняет команда в фоновом режиме в подоболочке. Оболочка не ждет для завершения, а статус возврата - 0.

    Команды, разделенные символом a; выполняются последовательно; оболочка ждет каждого команда для завершения по очереди. Статус возврата - это статус выхода последнего команда выполнена.                                   ...

    Список
  • ( список ) выполняется в среде подселочки
     {list; } просто выполняется в текущей среде оболочки.

  • A coprocess представляет собой команду оболочки, которой предшествует зарезервированное слово coproc. Копроцесс выполняется асинхронно в подоболочке...

  • $ Расширяется до идентификатора процесса оболочки. В() подоболочке она расширяется до ИД процесса текущей оболочки, а не подоболочки.

Примечания:

  • BASHPID Расширяется до идентификатора процесса текущего процесса bash. Это отличается от $$ при определенных обстоятельствах, таких как подоболочки, для которых не требуется bash повторно инициализирован.
  • BASH_SUBSHELL Приращение на единицу каждый раз при возникновении среды подоболочки или подоболочки. Начальное значение равно 0.

  • Для различий между использованием одиночной кавычки '' двойной кавычки "" вы можете увидеть этот вопрос. Давайте вспомним только, что если вы пишете команды в двойной кавычке "", переменные будут оцениваться с помощью расширения параметра из исходной оболочки, если extquote активирован по умолчанию от shopt. (cfr 4.3.2 Магазин, встроенный в справочное руководство bash)

    *extquote*Если установлено, в ${parameter} расширениях, заключенных в двойные кавычки, выполняется котировка $'string' и $"string". Эта опция включена по умолчанию.

Для дальнейших ссылок вы можете найти полезные, например,

Ответ 2

Я бы сказал, что нет.

Подселл обычно резервируется для любого экземпляра, где процессу оболочки необходимо выполнить операцию в изолированной среде, но с доступом к (копии) текущего состояния оболочки, включая все глобальные и локальные переменные.

Примеры:

  • Трубопроводы: echo x | read y
  • Подстановка команд: line=$( read < file && echo "$REPLY" )

В большинстве случаев это приведет к тому, что процесс оболочки начнет сканирование.

В последних обновлениях ksh93 некоторые подоболочки не могут фактически преобразовать новый процесс.

Суть дела в том, что подоболочка всегда создается неявно.

Запуск sh -c ... создаст процесс оболочки new, который отбросит большую часть состояния и начнет с нуля. Это означает, что обычные (локальные, глобальные) переменные оболочки исчезли. Естественно, новая оболочка будет иметь копию всех экспортированных переменных.


Другая интерпретация вопроса может быть Возможна ли опция -c для нового процесса для запуска ...? Ответ: Нет. Однако некоторые команды, переданные в аргумент -c, могут потребовать, чтобы оболочка породила подоболочку, точно так же, как если бы они были частью script или были введены в интерактивном режиме.

Ответ 3

Я тоже проверил его, и нет, я не думаю, что это (-c) вызывает подоболочку. Если мы ссылаемся на sh, да sh - это оболочка, которая вызвана, но не если она касается подоболочки внутри sh. Мы можем проверить это, выполнив команду, например:

# bash -c 'pstree -p; echo Value of PPID in Callee: $PPID; echo Callee PID: $BASHPID / $$'; echo "Caller PID: $$"
bash(28860)───bash(17091)───pstree(17092)
Value of PPID in Callee: 28860
Callee PID: 17091 / 17091
Caller PID: 28860

Как вы можете видеть, вызываемая оболочка (17091) и оболочка вызывающего (28860) связаны напрямую как дочерние элементы. Между ними нет ничего. $BASHPID и $$ одинаковы, и в этом случае они должны быть разными, если вы находитесь на подоболочке. Это просто говорит о том, что при вызове команд с -c не вызвано подселлем.

Для этого существует только одно особое поведение, то есть при вызове одного внешнего двоичного файла, например:

# bash -c 'pstree -p'; echo "Caller PID: $$"
bash(28860)───pstree(17124)
Caller PID: 28860

Там bash сохраняет себя от forking и решил просто непосредственно exec() единственную команду. Вы можете подумать, что, возможно, bash всегда делает это до последней команды, если команда ссылается на внешний исполняемый двоичный файл, но это не так:

# bash -c 'echo Value of PPID in Callee: $PPID; echo Callee PID: $BASHPID / $$; pstree -p'; echo "Caller PID: $$"
Value of PPID in Callee: 28860
Callee PID: 17128 / 17128
bash(28860)───bash(17128)───pstree(17129)
Caller PID: 28860

Теперь о

echo $BASHPID, $BASH_SUBSHELL

и

sh -c "echo $BASHPID, $BASH_SUBSHELL"

и результаты одинаковы.

Это должно быть то же самое, если echo $BASHPID, $BASH_SUBSHELL выполняется в той же оболочке, так как "echo $BASHPID, $BASH_SUBSHELL" сначала расширяется оболочкой, которая интерпретирует команду перед ее передачей в качестве аргумента sh. Если BASHPID, скажем, 28860 и BASH_SUBSHELL 0, то расширенное значение "echo $BASHPID, $BASH_SUBSHELL" равно 'echo 28860, 0', и в этом случае команда действительно будет sh -c 'echo 28860, 0'. Правильный способ этого состоит в том, чтобы использовать одну цитату, чтобы разрешить интерпретацию только в контексте новой вызываемой оболочки: sh -c 'echo $BASHPID, $BASH_SUBSHELL', хотя я не уверен, что сама команда будет полезна для тестирования.

Итак, в основном, я говорю, что тест echo $BASHPID, $BASH_SUBSHELL + sh -c "echo $BASHPID, $BASH_SUBSHELL" ничего не доказывает, если -c вызывает подоболочку или нет, и тот парень, который сказал вам, что он может ввести в заблуждение, поскольку переменные могут быть замененным правильно.

Тем не менее, мой собственный тест показал, что bash действительно не вызывает с ним подоболочку (-c).

Ответ 4

Проверьте это:

$ name=foo
$ echo $name
foo
$ sh -c "echo $name"
foo
$ sh -c 'echo $name'

$ 

Вам нужно ' вместо " в вашей команде. Else $name будет оцениваться до foo перед выполнением

И чтобы ответить на ваш вопрос, да, он создает/создает новую оболочку.

Ответ 5

sh будет порождать подоболочку. Но id подоболочки остается тем же самым

21934 pts/0    Ss     0:00 -bash
21963 pts/0    S      0:00  \_ /usr/bin/sudo -u root -H /bin/bash -c  export AUDITUSER=ch002854; cd $HOME && exec -a '-bash' /bin/bash
22031 pts/0    S      0:00      \_ -bash
 2969 pts/0    S      0:00          \_ sleep 1000
 2993 pts/0    S      0:00          \_ sleep 1000
 3726 pts/0    R+     0:00          \_ ps af

С sh -c он просто запустит команду. Это приведет к повторной инициализации переменных среды и, следовательно, сбросит значение $BASH_SUBSHELL на значение по умолчанию 0.

# sh -c 'echo $BASHPID, $BASH_SUBSHELL'
12671, 0

В то время как с помощью `` или() вы можете создать подоболочку

# (echo $BASHPID, $BASH_SUBSHELL)
13214, 1

Ответ 6

Независимо

Запуск этой простой строки покажет вам много:

$ echo $$;sh -c 'echo $$;ps axfw | grep -B2 $$'
14152
12352
14147 ?        S      0:00 xterm
14152 pts/4    Ss     0:00  \_ bash
12352 pts/4    S+     0:00      \_ sh -c echo $$;ps axfw | grep -B2 $$
12353 pts/4    R+     0:00          \_ ps axfw
12354 pts/4    S+     0:00          \_ grep -B2 12352

Это явно ребенок, но что такое подоболочка?

Ну, моя текущая рация оболочки pid равна 14152

$ echo $$ $BASHPID $BASH_SUBSHELL 
14152 14152 0
$ (echo $$ $BASHPID $BASH_SUBSHELL)
14152 12356 1
$ ( (echo $$ $BASHPID $BASH_SUBSHELL) )
14152 12357 2

Хорошо: BASHPID - это динамическая переменная , которая всегда принимает значение pid:

$ echo $BASHPID | sed \$a$BASHPID | sed \$a$BASHPID
12371
12372
12373

Hmmm где мой текущий рабочий pid?

$ sed "\$a$BASHPID $$" < <(echo "$BASHPID $$"| sed "\$a$BASHPID $$")
12386 14152
12387 14152
14152 14152

Ну, я их нашел!

$ echo $BASHPID $$;(echo $BASHPID $$;ps axfw | grep -B3 $BASHPID)
14152 14152
12469 14152
14152 pts/4    Ss     0:00  \_ bash
12469 pts/4    S+     0:00      \_ bash
12470 pts/4    R+     0:00          \_ ps axfw
12471 pts/4    S+     0:00          \_ grep -B3 12471

Заключение

Когда вы

$ echo $BASHPID $$ $BASH_SUBSHELL;(echo $BASHPID $$ $BASH_SUBSHELL)
14152 14152 0
12509 14152 1

используйте скобки или трубку (|), вы создадите подоболочку, которая является раздвоенным дочерним элементом запущенной оболочки.

Но когда вы

$ echo $BASHPID $$ $BASH_SUBSHELL;bash -c 'echo $BASHPID $$ $BASH_SUBSHELL'
14152 14152 0
12513 12513 0

Вы сжигете ребенка, запустив интерпретатор оболочки, так что это подоболочка, но не связанная с его родителем.

Nota: Если дочерний элемент не связан с его родителем, они используют одинаковые дескрипторы файлов ввода-вывода. Поэтому, если вы закроете свое окно (pts/4 в моем прогоне), вы отправите SIGHUP ко всему процессу, используя их.

Ответ 7

В этом ответе я думаю о подоболочке так же, как я думаю о подпроцессе.

Во-первых, не путайте переменное расширение. Если вы пишете переменную в двойных кавычках, она будет расширена вызывающей оболочкой, а не командой sh или -c. Так

sh -c "echo $$" 

дает вам PID вызывающей оболочки, потому что он расширяет $$ до того, как он вызывает sh, тогда как

sh -c 'echo $$' 

дает вам PID команды sh, которая была вызвана, поскольку одинарные кавычки указывают вызывающей оболочке передать строку $$ в sh без изменений.

Тем не менее, общий ответ на ваш вопрос:

  • Команда sh определенно является подоболочкой, вызывается родительской оболочкой, когда она видит "sh"
  • Когда вы отмечаете, что аргумент -c обрабатывается им как оболочка script, то вы видите, что вы получите грандиозную подошву вызванного sh, всякий раз, когда регулярная оболочка script получит один.

Подробнее об элементе 2: Некоторые встроенные оболочки создают подоболочки; другие - нет. Страница sh man рассказывает об этом; проверьте "if" builtin или constucts, которые используют backquotes ``. Использование труб также вызывает подоболочки. Вы также можете преднамеренно заставить подоболочку, заключая команды в круглые скобки. Тем не менее, включение команд в фигурные скобки {} НЕ делает сам по себе подоболочку.

sh предназначен для запуска команд, поэтому в большинстве случаев у вас будут подоболочки. Заметными исключениями являются "встроенный" случай, назначение переменных, настройка параметров и. команда.