Это было вызвано присутствием "drop-in" файла /etc/systemd/system/user@.service.d/dbus.conf
, который отменял "стандартное" определение user@.service
из /usr/lib/systemd/system
и, в частности, изменял DBUS_SESSION_BUS_ADDRESS
Как этот drop-in файл туда попал, остается загадкой. Согласно pacman -Qo
он не принадлежал ни одному пакету. Я предполагаю, что какой-то пакет добавил его, а затем он не был удален должным образом в последующем обновлении. Не уверен.
После удаления /etc/systemd/system/user@.service.d/dbus.conf
файла все работает нормально.
Если не смотреть слишком внимательно на ваш код, общий подход будет включать что-то вроде "защиты заголовков" C:
#ifndef HEADER_H
#define HEADER_H
/* The contents of the header file, with typedefs etc. */
#endif
где HEADER_H
- это макрос препроцессора C, специфичный для этого заголовка, используемый исключительно во избежание снова включить заголовок, если он уже был включен. Обычно я создаю макрос с именем, полученным из самого файла заголовка, например MCMC_H
для файла заголовка с именем mcmc.h
.
В сценарии оболочки это может быть так же просто, как
if [ -z "$script_source_guard" ]; then
script_source_guard=1
# ... do things (define functions etc.)
fi
Имя переменной script_source_guard
должно быть конкретным для этого файла. Опять же, имя может быть произвольно производным от имени исходного файла; файл с именем myfuncts.shlib
может иметь защитную переменную с именем MYFUNCTS
или _MYFUNCTS
или guard_myfuncts
или что-то еще.
Проблема масштаба. Как задумано, функция _source_script
фактически вызывая себя рекурсивно, поскольку это делает . ./${!arg}.sh
и поиск файлов, вызывающих _source_script
. Но переменные в сценариях оболочки по умолчанию являются глобальными. Таким образом, несколько воплощений функции _source_script
которые одновременно активны (в стеке ), используют одну и ту же копию arg
.
Подробно:
При вызове asserts.sh
или clean_environment.sh
_source_script scripts colors
функция _source_script
получает $#
= 2. И так работает цикл for (( arg = 2; arg <= $#; arg++ ))
а $arg
равно <= 2, поэтому в итоге получается 3. Когда вызывается . asserts.sh
, $arg
уже 3, потому что asserts
есть $3
в
_source_script scripts colors asserts clean_environment
команда в some_script.sh
. Таким образом, если для $arg
установленозначениеравное 3 в asserts.sh
, это в конечном итоге означает отсутствие операции -. — восстановление $arg
того, что уже было.
Но когда . clean_environment.sh
вызывают,$arg
равно 4, потому что clean_environment
есть $4
в
_source_script scripts colors asserts clean_environment
команда. Итак, если для $arg
установлено 3 в clean_environment.sh
(при вызове _source_script
), воплощение верхнего уровня -_source_script
(вsome_script.sh
)теряет свое место в цикле for (( arg = 2; arg <= $#; arg++ ))
, возвращается и снова выполняет . clean_environment.sh
. И снова, и снова, и снова…
Решение
Решение, конечно, состоит в том, чтобы просто поместить декларацию local arg
в функции _source_script
.
Другие примечания к вашим сценариям:
У вас такая ситуация:
.
(являются источником )файла (s ), содержащего определения, и Некоторые файлы входят в обе вышеуказанные группы; например, asserts.sh
и clean_environment.sh
предположительно предоставляют некоторые ресурсы своим вызывающим абонентам, но они также читают colors.sh
, чтобы получить определенные в нем значения. Предположительно существует иерархия:
some_script.sh
звонки colors.sh
some_script.sh
звонки asserts.sh
asserts.sh
звонки colors.sh
some_script.sh
звонки clean_environment.sh
clean_environment.sh
звонки colors.sh
и т. д.
Несколько пользователей предложили использовать «защиту заголовка». чтобы файлы команд оболочки не обрабатывались более одного раза. Хотя это предложение является хорошим и относится к вашей ситуации (как описано выше ), Я действительно не понимаю, какое отношение это имеет к вашему вопросу .
— за исключением того, что вы должны использовать его в самом_source_script.sh
.
В приведенной выше иерархии Я упустил тот факт, что каждый файл вызывает _source_script.sh
. Это означает, что функция _source_script
— это , переопределяемый во время работы . Это звучит потенциально очень опасно.
Ты говоришь
if [ "$#" -ge "1" ]
then
EXPECTED_DIR=$1
fi
︙
Вы могли бы также просто сказать
if [ "$#" -le 1 ]
then
exit 1 # or maybe return 1
fi
EXPECTED_DIR=$1
︙
потому что ничего не поделаешь, если аргументов меньше двух.
Безопаснее не использовать переменные в строке формата printf
. (, то есть первый аргумент ), если вы не уверены, что вам это нужно. Итак
printf "../${!arg}.sh\n"
printf "${RED}Script '${!arg}.sh' not loaded successfully. Exiting...${NORMAL}\n"
printf "No script loaded: $CURRENT_DIR != $EXPECTED_DIR.\n"
должно быть
printf "../%s.sh\n" "${!arg}"
printf "%sScript '%s.sh' not loaded successfully. Exiting...%s\n" \
"$RED" "${!arg}" "$NORMAL"
printf "No script loaded: %s != %s.\n" "$CURRENT_DIR" "$EXPECTED_DIR"
Вам следует чаще использовать кавычки.
../${!arg}.sh
должно быть
. "./${!arg}.sh"
и, строго говоря, быть действительно параноидально безопасным, $?
должно быть "$?"
.
Но вместо того, чтобы выполнять явный тест на "$?"
, почему бы просто не сказать
if !. "./${!arg}.sh"
then
printf "%sScript '%s.sh' not loaded successfully. Exiting...%s\n" \
"$RED" "${!arg}" "$NORMAL"
exit 1
fi
?
Обратите внимание, что команда .
, которая успешно установит $?
на статус выхода последней команды в файле. Будьте осторожны, чтобы файлы заголовков (файлы .sh
, которые определяют вещи, которые могут использоваться другими файлами )вернуть точный статус выхода.