Для всех вас, ребята, я нашел обходной путь, который работает для меня .. Может быть, это может вам помочь .. Вот оно:
Raid mount исчезает, потому что система не читает файл mdadm.conf во время загрузки или запуска. Итак, я отредактировал файл /etc/rc.d/rc.local
, включив в него следующие команды:
sleep 10
mdadm --assemble --scan
sleep 10
mount -a
Теперь, каждый раз, когда я перезагружаю систему, она читает этот файл, запускает упомянутые в нем команды и смонтировать raid mount ..
Похожий скрипт, без sudo
, но похожие результаты:
$ cat script.sh
#!/bin/bash
sed -e 's/^/--/'
whoami
$ bash < script.sh
--whoami
$ dash < script.sh
itvirta
С bash
остальная часть скрипта идет как вход в sed
, с dash
оболочка интерпретирует его.
Запуск strace
на тех: dash
считывает блок скрипта (восемь КБ здесь, более чем достаточно, чтобы вместить весь скрипт), а затем порождает sed
:
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 8192) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
Что означает, что filehandle находится в конце файла, и sed
не увидит никакого ввода. Оставшаяся часть буферизуется внутри dash
. (Если сценарий был длиннее размера блока 8 КБ, оставшаяся часть была бы прочитана sed
.)
Bash, с другой стороны, стремится вернуться к концу последней команды:
read(0, "#!/bin/bash\nsed -e 's/^/--/'\nwho"..., 36) = 36
stat("/bin/sed", {st_mode=S_IFREG|0755, st_size=73416, ...}) = 0
...
lseek(0, -7, SEEK_CUR) = 29
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|...
Если вход поступает из трубы, как здесь:
$ cat script.sh | bash
перемотка невозможна, так как трубы и раструбы не могут быть найдены. В этом случае Bash возвращается к чтению входных данных по одному символу за раз, чтобы избежать перечитывания. ( fd_to_buffered_stream()
in input.c
) Выполнение полного системного вызова для каждого байта в принципе не очень эффективно. На практике я не думаю, что чтение будет большим накладным расходом по сравнению, например, с тем фактом, что большинство вещей, которые делает оболочка, включают в себя порождение совершенно новых процессов.
Аналогичная ситуация такова:
echo -e 'foo\nbar\ndoo' | bash -c 'read a; head -1'
Подоболочка должна убедиться, что read
считывает только первую новую строку, так что head
видит следующую строку. (Это также работает с dash
.)
Другими словами, Bash делает все возможное, чтобы поддерживать чтение одного и того же источника для самого скрипта и для команд, выполняемых из него. dash
нет. zsh
и ksh93
, упакованные в Debian, идут с Bash в этом вопросе.
Оболочка читает сценарий из стандартного ввода. Внутри сценария вы запускаете команду, которая также хочет прочитать стандартный ввод.Какой вход куда пойдет? Точно не скажешь.
Оболочки работают следующим образом: они считывают фрагмент исходного кода, анализируют его и, если находят полную команду, выполняют ее, а затем продолжают работу с оставшейся частью фрагмента и остатком файла. Если фрагмент не содержит полной команды (с завершающим символом в конце — я думаю, что все оболочки читают до конца строки), оболочка читает другой фрагмент и так далее.
Если команда в сценарии пытается прочитать тот же файловый дескриптор, из которого оболочка читает сценарий, то команда найдет все, что идет после последнего прочитанного фрагмента. Это расположение непредсказуемо: оно зависит от того, какой размер фрагмента выбрала оболочка, и это может зависеть не только от оболочки и ее версии, но и от конфигурации машины, доступной памяти и т. д.
Bash ищет конец исходного кода команды. код в сценарии перед выполнением команды. Это не то, на что вы можете рассчитывать, не только потому, что другие оболочки этого не делают, но и потому, что это работает, только если оболочка читает из обычного файла. Если оболочка читает из канала (например, ssh remote-host.example.com
Если вы хотите передать ввод команде в скрипте, вам нужно сделать это явно, как правило, с помощью здесь. (Документ here обычно наиболее удобен для многострочного ввода, но подойдет любой метод.) Написанный вами код работает только в нескольких оболочках, только если скрипт передается в качестве входных данных оболочке из обычного файла; если вы ожидали, что второй whoami
будет передан в качестве входных данных для sudo …
, подумайте еще раз, имея в виду, что большую часть времени сценарий не передается на стандартный ввод оболочки.
#!/bin/bash
whoami
sudo su -l root <<'EOF'
whoami
EOF
Обратите внимание, что в этом десятилетии вы можете использовать sudo -i root
. Запуск sudo su
— это хак из прошлого.