Я написал сценарий, который переключает пользователей во время работы, и выполнил его, используя перенаправление файлов к стандартному в. Так user-switch.sh
что ...
#!/bin/bash
whoami
sudo su -l root
whoami
И запуск с этим bash
дает мне поведение, которое я ожидаю
$ bash < user-switch.sh
vagrant
root
Однако, если я запускаю скрипт с sh
, я получаю другой вывод
$ sh < user-switch.sh
vagrant
vagrant
Почему bash < user-switch.sh
дает другой результат, чем sh < user-switch.sh
?
Ноты:
- происходит на двух разных коробках под управлением Debian Jessie
bash
io-redirection
stdin
dash
popedotninja
источник
источник
sudo su
: unix.stackexchange.com/questions/218169/…/bin/sh
на (моя копия) Debian - это Dash, да. Я даже не знал, что это было до сих пор. Я застрял с Баш до сих пор.user-switch.sh
в работе Дженкинс, и это скрипт выполнялся. Запуск одного и того же сценария за пределами Jenkins дал разные результаты, и я прибегнул к перенаправлению файлов, чтобы получить поведение, которое я видел в Jenkins.Ответы:
Аналогичный скрипт
sudo
, но без схожих результатов:С
bash
, остальная часть сценария идет как вводsed
, сdash
, оболочка интерпретирует его.Работает
strace
на них:dash
читает блок скрипта (здесь восемь кБ, более чем достаточно для хранения всего скрипта), а затем порождаетsed
:Это означает, что дескриптор файла находится в конце файла и
sed
не будет видеть никаких входных данных. Оставшаяся часть буферизуется внутриdash
. (Если длина скрипта превышает размер блока 8 кБ, оставшаяся часть будет прочитанаsed
.)Bash, с другой стороны, ищет конец последней команды:
Если вход поступает из трубы, как здесь:
перематывать нельзя, так как трубы и розетки не доступны. В этом случае Bash возвращается к чтению ввода по одному символу за раз, чтобы избежать перечитывания. (
fd_to_buffered_stream()
вinput.c
) Выполнение полного системного вызова для каждого байта в принципе не очень эффективно. На практике, я не думаю, что чтения будут большими затратами по сравнению, например, с тем фактом, что большинство вещей, которые делает оболочка, порождает совершенно новые процессы.Похожая ситуация такая:
Подоболочка должна быть уверена, что
read
читает только первую новуюhead
строку , чтобы видеть следующую строку. (Этоdash
тоже работает .)Другими словами, Bash идет на дополнительные длины, чтобы поддерживать чтение одного и того же источника как для самого скрипта, так и для команд, выполняемых из него.
dash
не делает. Пакетzsh
иksh93
в Debian идут вместе с Bash.источник
strace
позже, и сравню результаты. Я не должен был использовать этот подход.Оболочка читает скрипт из стандартного ввода. Внутри скрипта вы запускаете команду, которая также хочет прочитать стандартный ввод. Какой вход будет идти куда? Вы не можете сказать достоверно .
Способ работы оболочек заключается в том, что они читают кусок исходного кода, анализируют его, и, если они находят завершенную команду, запускают команду, а затем переходят к оставшейся части фрагмента и оставшейся части файла. Если чанк не содержит завершенной команды (с завершающим символом в конце - я думаю, что все оболочки читаются до конца строки), оболочка читает другой чанк и так далее.
Если команда в сценарии пытается прочитать из того же дескриптора файла, из которого оболочка читает сценарий, то команда найдет все, что следует после последнего фрагмента, который она прочитала. Это местоположение непредсказуемо: оно зависит от того, какой размер блока выбрана оболочкой, и это может зависеть не только от оболочки и ее версии, но и от конфигурации компьютера, доступной памяти и т. Д.
Bash ищет конец исходного кода команды в сценарии перед выполнением команды. Это не то, на что вы можете рассчитывать, не только потому, что другие оболочки этого не делают, но и потому, что это работает только тогда, когда оболочка читает из обычного файла. Если оболочка читает из канала (например
ssh remote-host.example.com <local-script-file.sh
), прочитанные данные считываются и не могут быть прочитаны.Если вы хотите передать входные данные команде в сценарии, вы должны сделать это явно, обычно с документом здесь . (Здесь документ обычно наиболее удобен для многострочного ввода, но подойдет любой метод.) Написанный вами код работает только в нескольких оболочках, только если сценарий передается в качестве ввода в оболочку из обычного файла; если вы ожидали, что секунда
whoami
будет передана в качестве входных данныхsudo …
, подумайте еще раз, имея в виду, что большую часть времени сценарий не передается на стандартный ввод оболочки.Обратите внимание, что это десятилетие вы можете использовать
sudo -i root
. Бегsudo su
это взлом из прошлого.источник