Вопрос или проблема
Как предотвратить повторный запуск сценария bash при открытии терминала
Я физически подключен к машине и использую Arch Linux. Я использую арабский язык в терминале и использую BiCon для добавления поддержки двунаправленного текста в терминале (я использую st). Я хочу, чтобы программа запускалась автоматически при открытии терминала и очищала сообщение, которое она выводит при старте, поэтому я сделал скрипт:
$ cat biconscript
bicon
clear
и положил его в .bashrc, и вот вывод: строка bicon выполняется повторно.
Что я могу добавить в скрипт bash, чтобы он остановился после первого выполнения?
$ cat .bashrc
# Если выполняется не интерактивно, ничего не делать
[[ $- != *i* ]] && return
#alias ls="ls --color=auto"
alias ls="lsd"
alias grep='grep --color=auto'
alias p='sudo pacman'
alias ..='cd ..'
alias ...='cd ../../'
alias ....='cd ../../../'
alias ll="lsd -l -F"
alias la="lsd -aF "
alias sdn='sudo shutdown now'
alias q='exit'
alias update="p -Syu"
alias changeb='feh --bg-scale --randomize ~/Downloads/wall/'
export EDITOR=nvim #устанавливаем nvim как редактор по умолчанию
export MANPAGER="nvim +Man!"
PS1='\[\e[38;5;232;107m\]>\[\e[48;5;252m\]>\[\e[48;5;251m\]>\[\e[0m\] \[\e[38;5;26;1m\]@\[\e[0m\] \[\e[1m\]\w\[\e[38;5;46m\]$\[\e[0m\] '
set -o vi #установка режима vim
shopt -s autocd #не нужно вводить cd для смены каталога
PROMPT_DIRTRIM=2
eval "$(zoxide init bash)" #добавляет команду "z", связанную с приложением zoxide, она работает как команда "cd", но умнее
function yy() { # позволяет yazi существовать с изменением текущего каталога
local tmp="$(mktemp -t "yazi-cwd.XXXXXX")"
yazi "$@" --cwd-file="$tmp"
if cwd="$(cat -- "$tmp")" && [ -n "$cwd" ] && [ "$cwd" != "$PWD" ]; then
builtin cd -- "$cwd"
fi
rm -f -- "$tmp"
}
biconscript #скрипт для добавления арабского
Похоже, что bicon
всегда запускает новую сессию оболочки, и поэтому снова считывает ваш ~/.bashrc
, который затем снова вызывает bicon
, что снова считывает ваш ~/.bashrc
, что снова вызывает bicon
и так далее бесконечно. Это подразумевается в странице man
инструмента, которая гласит:
SHELL Если переменная SHELL существует, оболочка, созданная bicon, будет именно этой оболочкой. Если SHELL не установлена, предполагается оболочка Bourne. (Большинство оболочек устанавливают эту переменную автоматически).
Так что bicon
создает новую оболочку, вот почему вы это видите. Так что, боюсь, вы не можете добавить этот инструмент в ваш ~/.bashrc
так просто. Однако вы можете обернуть это в простой if
, который сначала проверяет, запущен ли экземпляр bicon
, и запускает его только в том случае, если такового нет:
if ! pkill -0 bicon; then
bicon
fi
clear
Важно, чтобы clear
было вне if
, потому что это должно выполняться созданной оболочкой, так что только если bicon
запущен. Теперь это работает, но это означает, что у вас будет работать bicon
только в первом открытом терминале и до его закрытия. Так что если вы откроете новый терминал, пока старый все еще работает, вы не получите bicon
в новом.
Чтобы обойти это, если вы используете bash
, вы можете воспользоваться переменной SHLVL
. См. man bash
:
SHLVL Увеличивается на единицу каждый раз, когда создается экземпляр bash.
Эта переменная считает количество экземпляров bash, которые вы запустили в текущей сессии. На графических системах она, вероятно, будет равняться 2
, когда вы открываете терминал, предположительно потому что ваша среда рабочего стола уже запущена в одном экземпляре bash:
Если вы откроете новую оболочку как другой пользователь, то она будет равна 1
:
terdon@oregano ~ $ sudo -iu bib
[bib@oregano ~]$ echo $SHLVL
1
[bib@oregano ~]$
Итак, предполагая, что ваша система похожа на мою и у вас 2
для новых терминалов, вы можете добавить это в ваш ~/.bashrc
:
if [ $SHLVL -le 2 ]; then
bicon
fi
clear
Это запустит bicon
только один раз для каждого открытого терминала.
Проверьте на своей системе, проверьте, равен ли в новом терминале ваш SHLVL
1 или 2, и адаптируйте соответственно (возможно, вы захотите использовать -le 1
вместо -le 2
, если ваше значение равно 1).
Проблема заключается в рекурсивном запуске новых оболочек.
Во-первых, проверьте документацию для bicon
, чтобы узнать, есть ли у него режим или опция, которая не запускает новую оболочку.
Если это не сработает, читайте дальше…
Дело в том, чтобы делать вещи, которые по своей природе рекурсивны, а затем добавлять дополнительный код для предотвращения рекурсии, создает хрупкий дизайн. Вы можете оказаться заблокированным, сделав незначительное изменение в вашем .bash_profile.
Подумайте о замене вашей оболочки для входа с bash
на что-то, что устанавливает SHELL=/bin/bash
, а затем запускает bicon
; это станет программой, которая запускается в каждом новом терминале.
Вероятно, это будет скрипт в вашем каталоге ~/.local/bin
или ~/bin
, и вам придется указать его полный путь:
b=$( command -v bicon )
s=$HOME/.bin/bicon-login
mkdir -p "${s%/*}"
printf > "$s" '%s\n' \
'#!/bin/bash' \
"SHELL=/bin/bash exec -l $b"
chmod a=rx "$s"
sudo usermod -s "$s" "$USER"
Обратите внимание, что строка #!/bin/bash
независима от вашей оболочки для входа; я выбрал bash
, потому что он поддерживает exec -l
, который говорит bicon
, что это на самом деле ваша оболочка для входа.
Наконец, ваша программа терминала могла быть настроена на использование bash
явно. Это следует отключить, чтобы использовать вашу оболочку для входа.
Ответ или решение
Чтобы предотвратить повторный запуск вашего скрипта в начале терминала при использовании Bash, результатом чего является бесконечный цикл, необходимо рассмотреть несколько аспектов. Проблема возникает из-за того, что bicon
запускает новый экземпляр оболочки, которая затем снова считывает ваш файл .bashrc
и вновь запускает bicon
. Вот несколько решений для этой проблемы.
Решение 1: Использование переменной SHLVL
Один из простых способов избежать бесконечного цикла — использование переменной окружения SHLVL
, которая отслеживает уровень вложенности оболочек. В своем файле .bashrc
, вы можете добавить условие, проверяющее значение этой переменной. Например:
if [ "$SHLVL" -le 2 ]; then
bicon
fi
clear
Этот код запускает bicon
только в первых двух уровнях оболочки. Проверьте значение SHLVL
в новом терминале, выполнив команду echo $SHLVL
, чтобы удостовериться, что ваше значение соответствует настройки, и при необходимости измените условие.
Решение 2: Проверка запущенных процессов
Также возможно использовать команду pkill
для проверки, запущен ли уже процесс bicon
, и запускать его только в случае, если он неактивен:
if ! pgrep -x "bicon" > /dev/null; then
bicon
fi
clear
С помощью pgrep
мы проверяем, работают ли экземпляры bicon
, и запускаем его только в том случае, если ни одного экземпляра не найдено. Это предотвращает повторный запуск bicon
, если он уже активен.
Решение 3: Изменение оболочки по умолчанию
Если вышеописанные методы вам не подходят, вы можете рассмотреть возможность изменения вашей входной оболочки на пользовательский скрипт, который запускает bicon
при входе. Создайте скрипт, который будет использовать bicon
следующим образом:
#!/bin/bash
SHELL=/bin/bash exec -l bicon
Сохраните его в директории ~/.local/bin/bicon-login
, сделайте его исполняемым и измените оболочку вашего пользователя с помощью команды:
sudo usermod -s ~/.local/bin/bicon-login $USER
Дополнительные рекомендации
- Тестируйте скрипт на локальной машине, чтобы убедиться, что он работает, как ожидается.
- Обратите внимание на конфигурацию вашего терминала: Некоторые терминалы могут быть настроены для использования конкретной оболочки. Вы можете изменить это в настройках терминала, чтобы использовать вашу входную оболочку.
- Чистка файла .bashrc: Избегайте добавления множества сложных условий, которые могут привести к ошибкам.
Эти решения помогут вам избежать проблем с повторным запуском bicon
в вашей терминальной среде на Arch Linux.