Как рекурсивно исходить из сценариев оболочки?

Это было вызвано присутствием "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 файла все работает нормально.

2
26.06.2019, 08:21
2 ответа

Если не смотреть слишком внимательно на ваш код, общий подход будет включать что-то вроде "защиты заголовков" 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 или что-то еще.

2
27.01.2020, 22:19

Проблема масштаба. Как задумано, функция _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_scriptsome_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, которые определяют вещи, которые могут использоваться другими файлами )вернуть точный статус выхода.

2
27.01.2020, 22:19

Теги

Похожие вопросы