Есть ли подоболочка, созданная при запуске команды "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
Независимо bash
Запуск этой простой строки покажет вам много:
$ 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 предназначен для запуска команд, поэтому в большинстве случаев у вас будут подоболочки. Заметными исключениями являются "встроенный" случай, назначение переменных, настройка параметров и. команда.