Существует ли подоболочка, созданная при запуске команды `sh -c "command"`, новая оболочка или ничего из этого?
В bash, когда я запускаю следующую команду:
sh -c "command"
там создан подоболочка, а затем command
выполняется?
Я предполагаю, что команда будет работать в текущей оболочке, но я не уверен. Это предположение исходит из того факта, что я уже тестировал с помощью следующих команд:
echo $BASHPID, $BASH_SUBSHELL
а также
sh -c "echo $BASHPID, $BASH_SUBSHELL"
и результаты одинаковы. Но это может немного вводить в заблуждение, как кто-то сказал мне, потому что переменные могут быть заменены до выполнения команды. Это правда?
7 ответов
Я думаю, что с примерами можно понять ситуацию
(в моем случае 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)) Я сообщаю о некоторых важных моментах появления подоболочки:
Каждая команда в конвейере выполняется как отдельный процесс (т. Е. В подоболочке).
Если команда завершается оператором управления &, оболочка выполняет команду в фоновом режиме в подоболочке. Оболочка не ожидает завершения команды, и статус возврата равен 0.
Команды, разделенные; выполняются последовательно; оболочка ожидает завершения каждой команды по очереди. Статус возврата - это статус выхода последней выполненной команды....
( список ) список выполняется в среде подоболочки
{список; } список просто выполняется в текущей среде оболочки.Копроцесс - это команда оболочки, которой предшествует зарезервированное слово coproc. Сопроцесс выполняется асинхронно в подоболочке...
$ Расширяется до идентификатора процесса оболочки. В подоболочке() она расширяется до идентификатора процесса текущей оболочки, а не подоболочки.
Примечания:
BASHPID
Расширяется до идентификатора процесса текущего процесса bash. Это отличается от$$
при определенных обстоятельствах, таких как подоболочки, которые не требуют повторной инициализации bash.BASH_SUBSHELL
Увеличивается на единицу каждый раз, когда создается среда подоболочек или подоболочек. Начальное значение 0.Для различий между использованием одинарной кавычки
''
двойная цитата""
Вы можете увидеть этот вопрос. Пусть помнят только то, что если вы пишете команды в двойных кавычках""
переменные будут оцениваться с помощью раскрытия параметров из исходной оболочки, если extquote включен, как это по умолчанию изshopt
, (см. 4.3.2 Встроенный модуль в Справочном руководстве Bash)*extquote*
Если установлено, кавычки $'string' и $"string" выполняются в расширениях ${parameter}, заключенных в двойные кавычки. Эта опция включена по умолчанию.
Для дальнейших ссылок вы можете найти полезные, например,
man bash
,- Секция
Shell Expansions
руководства по bash. - Раздел двойных кавычек или
- Расширение параметров языка команд оболочки, как определено в Открытой группе базовых спецификаций, выпуск 6 IEEE Std 1003.1, выпуск 2004 года.
Я бы сказал, нет.
Подоболочка обычно зарезервирована для любого случая, когда процесс оболочки должен выполнить операцию в изолированной среде, но с доступом (копией) к текущему состоянию оболочки, включая все глобальные и локальные переменные.
Примеры:
- Трубопроводы:
echo x | read y
- Подстановка команд:
line=$( read < file && echo "$REPLY" )
В большинстве случаев это приведет к тому, что процесс оболочки разветвляется сам.
В последних обновлениях ksh93 некоторые подоболочки могут фактически не форкировать новый процесс.
Суть в том, что подоболочка всегда создается неявно.
Бег sh -c ...
создаст новый процесс оболочки, который отбросит большую часть состояния и начнет с нуля. Это означает, что нормальные (локальные, глобальные) переменные оболочки исчезли. Естественно, новая оболочка будет иметь копию всех экспортируемых переменных.
Другая интерпретация вопроса может быть -c
опция fork новый процесс для запуска ...
? Ответ: Нет. Это не так. Тем не менее, определенные команды передаются в -c
Аргумент может потребовать, чтобы оболочка порождала подоболочку, как если бы она была частью скрипта или вводилась в интерактивном режиме.
Я также проверил это, и нет, я не думаю, что это (-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 спасает себя от разветвления и решил просто напрямую выполнить 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
).
Проверь это:
$ name=foo
$ echo $name
foo
$ sh -c "echo $name"
foo
$ sh -c 'echo $name'
$
Тебе нужно '
вместо "
в вашей команде. еще $name
будет оценен в foo
перед казнью
И чтобы ответить на ваш вопрос, да, он создает / порождает новую оболочку.
Sh порождает подоболочку. Но идентификатор subshell остается прежним
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
Независимо от удара
Выполнение этой простой строки покажет вам многое:
$ 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
Хммм, где мой текущий рабочий пид?
$ 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
Вы сожжете ребенка, запустив интерпретатор оболочки, так что это недоработка, но не связанная с его родителем.
Примечание: если ребенок не связан с родителем, они используют одинаковые дескрипторы файлов ввода-вывода. Так что, если вы закроете окно (pts/4
в моем прогоне), вы отправите SIGHUP всем процессам, использующим их.
В этом ответе я думаю о подоболочке точно так же, как и о подпроцессе.
Прежде всего, не смущайтесь расширением переменных. Если вы напишите переменную в двойных кавычках, она будет раскрыта вызывающей оболочкой, а не командой sh или ее -c. Так
sh -c "echo $$"
дает PID вызывающей оболочки, потому что она расширяет $$ до вызова sh, тогда как
sh -c 'echo $$'
выдает PID команды sh, которая была вызвана, потому что одинарные кавычки сообщают вызывающей оболочке передать строку $$ в sh без изменений.
Тем не менее, общий ответ на ваш вопрос:
- Команда sh, безусловно, является подоболочкой, вызываемой родительской оболочкой, когда она видит 'sh'
- Когда вы заметите, что аргумент -c рассматривается им как сценарий оболочки, вы увидите, что вы получите грандиозную оболочку вызванного sh всякий раз, когда его получит обычный сценарий оболочки.
Больше на предмете 2: Некоторые встроенные оболочки создают подоболочки; другие нет. Страница man sh говорит об этом; проверьте встроенное "if" или конструкции, которые используют обратные кавычки ``. Использование труб также вызывает появление подоболочек. Вы также можете сознательно форсировать подоболочку, заключая команды в скобки. Однако включение команд в фигурные скобки {} само по себе НЕ вызывает подоболочку.
sh предназначен для запуска команд, так что в большинстве случаев у вас будут подоболочки. Заметными исключениями являются встроенный регистр, назначение переменных, настройка параметров и. команда.