Вопрос или проблема
Я использую Ubuntu 22 (“22.04.4 LTS (Jammy Jellyfish)”)
Я понимаю, что в любом скрипте оболочки Linux символ $$ обозначает идентификатор процесса (PID) процесса, выполняющего этот скрипт.
У меня есть скрипт оболочки, который должен гарантировать, что он выполняется в оболочке Bourne, поэтому он определяет, в какой оболочке он выполняется. Это определение оболочки необходимо, потому что в скрипте много кода, специфичного для оболочки Bourne, который не является переносимым.
Таким образом, чтобы гарантировать, что этот скрипт выполняется в оболочке Bourne, помимо шебанга я решил добавить еще одну проверку для определения, какая оболочка выполняет скрипт. Это связано с тем, что некоторые пользователи склонны явно указывать оболочку, тем самым переопределяя шебанг.
Посмотрите следующий фрагмент кода из моего скрипта оболочки, который определяет оболочку, в которой выполняется скрипт. Он использует $$ и находит имя процесса с PID=$$; это работает нормально если нет шебанга в начале скрипта.
runshell=`ps -p $$ |grep -v PID| awk '{print $4}'`
if [ $runshell != "sh" ]
then
echo " оболочка это $runshell"; exit 99;
echo "Вы должны запустить это в оболочке Bourne. Выход из программы"
exit 99;
fi
echo "Запуск в оболочке Bourne."
# остальная часть кода, который нужно выполнить в оболочке Bourne
Пока нет шебанга, вышеуказанный скрипт работает очень хорошо (переменная “runshell” имеет значение оболочки, выполняющей скрипт).
Однако если я введу шебанг следующим образом, тогда имя процесса с PID $$ оказывается именем скрипта, набранного в командной строке. Таким образом, в приведенном ниже фрагменте переменная ‘runshell’ получает значение = .
#!/bin/sh
runshell=`ps -p $$ |grep -v PID| awk '{print $4}'`
if [ $runshell != "sh" ]
then
echo " оболочка это $runshell"; exit 99;
echo "Вы должны запустить это в оболочке Bourne. Выход из программы ";
exit 99;
fi
# остальная часть кода, который нужно выполнить в оболочке Bourne
Когда я запускаю этот скрипт как
“./script.sh ”
тогда происходит описанная проблема.
Однако если я запускаю его, указывая оболочку как
“sh script.sh”
тогда он правильно определяет оболочку.
Итак, вопросы:
- Почему шебанг должен влиять на значение $$ (и, следовательно, на имя процесса с PID $$)?
- И если мне нужно сохранить шебанг, как мне определить оболочку, в которой выполняется скрипт?
Спасибо за вашу помощь.
Я нашел обходное решение.
Если вы просмотрите список процессов изнутри скрипта, используя полный формат отображения (ps -ef), вы сможете увидеть, что полный формат действительно дает вам представление о используемой оболочке.
Это работало во всех случаях, которые я изучал, то есть с шебангом или без него и с использованием оболочки по умолчанию или указанием другой оболочки (Bourne или другой). Так что пока я переключился на использование вывода ps -f для определения оболочки вместо $$. См. ниже:
$sh test.sh
UID PID PPID C STIME TTY TIME CMD
myuser 74162 73468 0 09:53 pts/1 00:00:00 sh test.sh
$./test.sh
UID PID PPID C STIME TTY TIME CMD
root 74148 73468 0 09:53 pts/1 00:00:00 /bin/sh
$bash test.sh
UID PID PPID C STIME TTY TIME CMD
root 74572 73468 0 10:02 pts/1 00:00:00 bash test.sh
Таким образом, мой работающий фрагмент кода, используя производную полного формата списка (вместо полагания на $$), выглядит следующим образом:
#!/bin/sh
runshell=$(ps -ef |grep $0 |grep -v grep | awk '{print $8}'| sort -u)
if [ "$runshell" != "sh" ] && [ "$runshell" != "/bin/sh" ]
then
echo " вы НЕ используете оболочку Bourne - выходим"
exit 99
fi
echo " вы используете оболочку Bourne "
# выполняем код, специфичный для оболочки Bourne
Ответ или решение
Чтобы понять, как правильно определить, под какой оболочкой выполняется ваш скрипт на Linux, начнем с прояснения терминологии и поведения системы.
1. Влияние shebang на значение $$
Символ «$$» в shell-скрипте обозначает идентификатор процесса (PID) текущего скрипта. Когда вы добавляете строку shebang (например, #!/bin/sh
) в начало вашего скрипта, это определяет, какая оболочка будет использоваться для выполнения этого скрипта. В случае, когда скрипт запускается напрямую (например, с помощью ./script.sh
), операционная система создает новый процесс, который будет запускаться с указанной оболочкой.
Если shebang отсутствует, сам скрипт выполняется в оболочке, из которой он был вызван, и «$$» указывает на PID вызывающей оболочки. Однако при наличии shebang значение «$$» указывает на PID новой оболочки (которая интерпретирует скрипт), а не на оболочку, из которой была вызвана команда.
2. Как определить оболочку с shebang
Чтобы внести ясность и избежать дополнительных проверок с использованием «$$», вы можете использовать более надежные методы, такие как просмотр процесса, который вызывает текущий скрипт. Путем изменения вашего скрипта для использования команды ps
, вы сможете точно определить оболочку, в которой он выполняется, независимо от наличия shebang.
Пример исправленного скрипта
Вот пример вашего скрипта с учётом вышеупомянутых доработок:
#!/bin/sh
# Получаем имя оболочки, используя более надежный метод
runshell=$(ps -p $$ -o cmd= | awk '{print $1}')
if [[ "$runshell" != "sh" && "$runshell" != "/bin/sh" ]]
then
echo "Вы не используете оболочку Bourne! Завершение работы."
exit 99
fi
echo "Вы используете оболочку Bourne."
# Здесь размещается код, специфичный для оболочки Bourne
Заключение
Подводя итог, можно сказать, что определение оболочки, в которой выполняется скрипт, может быть достигнуто умением корректно использовать команду ps
для получения информации о процессе, а также пониманием влияния shebang на выполнение скрипта. Избегая использования «$$» для идентификации оболочки при наличии shebang, вы сможете сделать ваш скрипт более стабильным и переносимым.
Если у вас возникнут дополнительные вопросы или потребуется уточнение, не стесняйтесь обращаться!