Опасное поведение встроенной команды cd

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

Я шел вперед, работая над shell-скриптом, и только что узнал кое-что, что оказалось для меня удивительным. Я представляю это здесь в виде вопроса, потому что хотел бы узнать, есть ли способ избежать этого.

Вот сценарий: cd в папку, которая определяется как переменная; за исключением того, что имя переменной написано с ошибкой в команде cd:

$ TGT_FLDR=/home/seamus/logs/
$ cd $TGT_FLDF
$ echo $?
0
$ pwd
/home/seamus
$

Я узнал об этом, тестируя скрипт:

TGT_FLDR=/home/seamus/logs/
...
cd $TGT_FLDF
if [ -n "$(ls -A)" ]; then
    rm *
fi
### ОЙ!!!

Это показалось мне довольно опасным поведением. Поскольку cd является встроенной командой bash (по крайней мере, на моей системе), я проверил cd --help. Один пункт выделился:

Если каталог не найден, и настроена опция оболочки `cdable_vars`, то слово предполагается как имя переменной. Если эта переменная имеет значение, то ее значение используется как DIR.

Это утверждение кажется мне мало понятным, но оно предполагает, что где-то определена “опция оболочки” cdable_vars, что она определена и может быть определена как $HOME.

Я думаю, что хотел бы изменить значение cdable_vars, но где определена эта опция оболочки?

В вашем использовании TGT_FLDF нет ничего “неправильного”. Скрипт мог быть написан с предположением, что TGT_FLDF унаследован из окружения.

Обратите внимание, что cd $TGT_FLDF выполняется просто как cd, если $TGT_FLDF пустое, что изменяет ваш рабочий каталог на домашний каталог. Опция оболочки cdable_vars не влияет на это. Опция cdable_vars позволяет, например, выполнить cd mydir, чтобы изменить рабочий каталог на $mydir, когда mydir не существует, при этом mydir является переменной оболочки, содержащей путь к каталогу.

Применение общих стратегий защитного программирования и использование set -u или set -o nounset возможно предотвратили бы эту проблему. Использование set -u сделало бы ошибкой развертывание неопределенной переменной (и скрипт был бы завершен). Это по-прежнему вызвало бы ту же проблему, если бы TGT_FLDF была установлена, но пуста, очевидно.

Другой хорошей идеей было бы запускать shellcheck на коде перед его выполнением. Это указывало бы на использование, казалось бы, неопределенной переменной, что она использовалась без кавычек, и что * в rm * могло означать, что некоторые имена файлов будут интерпретироваться как опции для rm.


Если вы хотите очистить каталог, безусловное удаление и восстановление его легче, чем попытка обнаружить, пустой ли он, а затем перечислить все имена в нем (фактически дважды просматривая его содержимое). Это позволяет избежать возможного присутствия слишком большого количества файлов для обработки с rm -- * (что также нарушило бы вашу проверку с ls -A).

#!/bin/sh -u

logdir=$HOME/logs

rm -r -- "$logdir"
mkdir -p -- "$logdir"

.

Ответ или решение

Использование встроенной команды cd в Bash требует внимательности и соблюдения осторожности, особенно во время написания скриптов. В этом контексте можно выделить несколько моментов, которые помогут предотвратить потенциально опасное поведение, связанное с возможностью неправильно указать имя переменной, как это показано в приведенном сценарии.

Теория

Основной проблемой в представленном случае является то, что неправильно указанная переменная TGT_FLDF приводила к выполнению команды cd без аргумента. Это, в свою очередь, вызывает переход в домашний каталог пользователя, поскольку такая является стандартным поведением cd в отсутствии указанного пути. Этот нюанс становится особенно опасным в сценариях, где последующие команды работают с файлами в предполагаемом каталоге, что может привести к случайному удалению или изменению файлов в домашней директории.

Важным аспектом в этом контексте является опция cdable_vars. В случае ее установки, Bash может использовать значение переменной, если путь, переданный в cd, не существует как каталог. Однако, как правильно отмечено, эта опция не влияет на случай, когда переменная пуста, и cd возвращает домашнюю директорию.

Пример

Рассмотрим ситуацию, где скрипт должен перемещаться в указанный каталог TGT_FLDR и выполнять определенные действия, такие как очистка содержимого этого каталога. При неправильной орфографии переменной cd будет выполнена с пустым значением, что перенаправит в домашнюю директорию.

TGT_FLDR=/home/seamus/logs/
cd $TGT_FLDF
if [ -n "$(ls -A)" ]; then
    rm *
fi

Применение

Для предотвращения таких ошибок можно использовать несколько подходов:

  1. Включение строгого режима ошибок: Используйте set -u или set -o nounset в начале скрипта. Это приведет к завершению выполнения скрипта, если попытаться обратиться к неустановленной переменной.

  2. Очистка и переразмещение каталога: Вместо попытки очистить содержимое каталога, лучше удалить и заново создать его. Это гарантирует, что действия применяются в нужном месте.

#!/bin/bash -u

logdir=$HOME/logs

rm -r -- "$logdir"
mkdir -p -- "$logdir"
  1. Инструменты для статического анализа: Используйте shellcheck для анализа скриптов на наличие частых ошибок, таких как неустановленные или неиспользуемые переменные.

Эти методы помогут не только избежать ошибочного поведения команды cd, но и улучшат общую надежность и безопасность ваших скриптов. Таким образом, можно минимизировать риск случайного удаления или изменения критичных данных, обеспечивая преднамеренное и контролируемое выполнение скриптов.

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

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