Как определить оболочку, в которой выполняется мой скрипт; проблема, потому что шебанг влияет на вывод $$

Вопрос или проблема

Я использую 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”
тогда он правильно определяет оболочку.

Итак, вопросы:

  1. Почему шебанг должен влиять на значение $$ (и, следовательно, на имя процесса с PID $$)?
  2. И если мне нужно сохранить шебанг, как мне определить оболочку, в которой выполняется скрипт?

Спасибо за вашу помощь.

Я нашел обходное решение.
Если вы просмотрите список процессов изнутри скрипта, используя полный формат отображения (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, вы сможете сделать ваш скрипт более стабильным и переносимым.

Если у вас возникнут дополнительные вопросы или потребуется уточнение, не стесняйтесь обращаться!

Оцените материал
Добавить комментарий

Капча загружается...