Shell-скрипт, который удалил базу данных, и история о том, как ShellCheck мог бы помочь это предотвратить +55


AliExpress RU&CIS

Сегодня хочу рассказать об одном случае из жизни, когда невинная ошибка при написании скрипта командной оболочки привела к удалению базы данных, используемой в продакшне. Расскажу я и о том, как ShellCheck (инструмент для линтинга и анализа скриптов, выходящий под лицензией GPLv3) мог бы обнаружить эту ошибку и предотвратил бы катастрофу. Да, сразу скажу, что я — автор ShellCheck.



Происшествие


Вот — описание того печального происшествия, о котором я хочу рассказать. Следующее я взял из поста на StackOverflow:

Наш разработчик закоммитил код с огромной ошибкой и мы нигде не можем найти нашу базу данных MongoDB. Пожалуйста, спасите нас!!!

Он вошёл на сервер и сохранил следующий код в ~/crontab/mongod_back.sh:

#!/bin/sh
DUMP=mongodump
OUT_DIR=/data/backup/mongod/tmp     // ????????
TAR_DIR=/data/backup/mongod         // ????????
DATE=`date +%Y_%m_%d_%H_%M_%S`      // ????????????
DB_USER=Guitang                     // ??????
DB_PASS=qq____________              // ????????
DAYS=14                             // ????14????
TAR_BAK="mongod_bak_$DATE.tar.gz"   // ????????
cd $OUT_DIR                         // ?????
rm -rf $OUT_DIR/*                   // ??????
mkdir -p $OUT_DIR/$DATE             // ?????????
$DUMP -d wecard -u $DB_USER -p $DB_PASS -o $OUT_DIR/$DATE  // ??????
tar -zcvf $TAR_DIR/$TAR_BAK $OUT_DIR/$DATE       // ????????????
find $TAR_DIR/ -mtime +%DAYS -delete             // ??14??????

А потом выполнил команду ./mongod_back.sh, после чего последовало множество сообщений об отказе в доступе. Дальше — он нажал Ctrl + C и сервер автоматически выключился.

Потом он связался с AliCloud, инженер подключил диск к другому, работающему серверу, что позволило бы нашему разработчику проверить диск. Далее, он понял, что некоторые папки куда-то пропали, включая /data/, где была база данных MongoDB!

P.S. Он не сделал снепшот диска.

В общем то это — кошмар для любого инженера.

Анализ причин данного происшествия — это интересная задачка, для решения которой достаточно будет базовых навыков написания Shell-скриптов. Если вы хотите попытаться сами во всём разобраться — попробуйте, сейчас — самое время это сделать. А если вам нужны подсказки — вот что выдал ShellCheck после анализа данного скрипта.

Далее я в подробностях разберу этот случай и расскажу о том, как ShellCheck мог бы предотвратить катастрофу.

Что пошло не так?


Вот — код минимального воспроизводимого примера (MCVE), запуск которого позволит любому всерьёз и надолго испортить себе жизнь:

#!/bin/sh
DIR=/data/tmp    // Директория, которую нужно удалить
rm -rf $DIR/*    // Удаление директории

Тут имеется одна фатальная ошибка, которая заключается в том, что последовательность // в shell-скриптах — это не комментарий. Это — путь к корневой директории, аналогичный /.

На некоторых платформах строка с командой rm сама по себе может привести к тяжёлым последствиям, так как она сводится к rm -rf / с ещё несколькими аргументами. Правда, реализация этой команды в наши дни часто такого не позволяет. Случай, о котором я рассказал, произошёл на Ubuntu, а в ней GNU-реализация rm не дала бы выполнить такую команду:

$ rm -rf //
rm: it is dangerous to operate recursively on '//' (same as '/')
rm: use --no-preserve-root to override this failsafe

Система сообщает о том, что опасно проводить рекурсивные действия над директорией // (что то же самое, что и /), и предлагает, если надо, отключить эту защитную меру, с помощью опции --no-preserve-root.

Именно тут в игру вступает команда присвоения значения переменной.

Оболочка воспринимает присвоение значения переменной и команды как две стороны одной медали. Вот что сказано об этом в стандарте POSIX:

«Простая команда» — это последовательность необязательных команд присвоения значений и перенаправлений, расположенных в любом порядке, за которыми, что тоже необязательно, следуют слова и перенаправления. Эта последовательность завершается оператором управления.

(«Простая команда» отличается от «сложной команды», которая представляет собой структуру наподобие инструкций if или циклов for, содержащую одну или большее количество простых или сложных команд.)

Это означает, что var=42 и echo «Hello» — это простые команды. В первой имеется одно необязательное присвоение значения и нет необязательных слов. Во второй нет необязательных присвоений значений, но есть два необязательных слова.

Это так же означает, что в состав отдельной простой команды может входить и то и другое: var=42 echo «Hello».

Если не вдаваться в подробности стандарта, то окажется, что операция присвоения значения переменной в простой команде действительна только при выполнении вызванной команды. А если в простой команде нет имени команды — команда присвоения действует на уровне текущей оболочки. Последнее из вышеприведённых утверждений объясняет конструкцию var=42. А вот с первым утверждением, пожалуй, стоит разобраться.

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

$ echo "$PAGER"  # Показать текущее значение переменной PAGER
less

$ PAGER="head -n 5" man ascii
ASCII(7)       Linux Programmer's Manual      ASCII(7)

NAME
       ascii  -  ASCII character set encoded in octal,
       decimal, and hexadecimal

$ echo "$PAGER"  # Текущее значение PAGER не изменилось
less

Именно это нечаянно и было сделано в вышеописанном случае. Так же, как в предыдущем примере новое значение PAGER действовало лишь во время выполнения команды man, тогда область действия DIR была ограничена //:

$ DIR=/data/tmp    // Директория, которую нужно удалить
bash: //: Is a directory

$ echo "$DIR"  # Переменная не установлена
(эта команда ничего не выводит)

Это значит, что конструкция rm -rf $DIR/* превратилась в rm -rf /* и в итоге её не отловила проверка, ориентированная на rm -rf /.

(А почему команда rm просто не отказывалась бы выполняться и при передаче ей /*? Дело в том, что она не видит конструкцию /*, так как оболочка сначала раскрывает эту конструкцию и команда rm видит лишь /bin /boot /dev /data и так далее. Хотя rm, очевидно, может отказать пользователю и в удалении директорий первого уровня, это уже начнёт мешать правильному применению данной команды, что, в соответствии с философией Unix — тяжкий грех.)

Как ShellCheck мог бы помочь предотвратить эту проблему?


Проанализируем в ShellCheck опасный фрагмент скрипта, который, напомню, выглядит так:

#!/bin/sh
DIR=/data/tmp    // The directory to delete
rm -rf $DIR/*    // Now delete it

Вот что у нас получилось (тут можно поэкспериментировать с интерактивным примером):

$ shellcheck myscript

In myscript line 2:
DIR=/data/tmp    // The directory to delete
                 ^-- SC1127: Was this intended as a comment? Use # in sh.

In myscript line 3:
rm -rf $DIR/*    // Now delete it
       ^----^ SC2115: Use "${var:?}" to ensure this never expands to /* .
       ^--^ SC2086: Double quote to prevent globbing and word splitting.
                 ^-- SC2114: Warning: deletes a system directory.

Мы уже обсудили две проблемы этого скрипта, своевременное обнаружение которых могло бы помочь предотвратить неприятности:

  • Анализатор ShellCheck обратил внимание на то, что первая последовательность //, вероятно, была задумана как комментарий (вики-страница SC1127).
  • ShellCheck указал на то, что вторая последовательность // приведёт к воздействию на системную директорию (вики-страница SC2114).

А третье замечание программы относится к универсальным способам защиты от ошибок. И применение этого совета, даже если оставить без внимания две предыдущих рекомендации, тоже позволило бы предотвратить катастрофу:

  • ShellCheck предложил использовать конструкцию вида rm -rf ${DIR:?}/* для того чтобы остановить выполнение команды в том случае, если переменная по любой причине будет пустой или неустановленной (вики-страница SC2115).

Это свело бы на нет последствия целой плеяды ошибок, способных привести к тому, что переменная окажется пустой, включая echo /tmp | read DIR (подоболочки), DIR= /tmp (неправильная расстановка пробелов) и DIR=$(echo /tmp) (потенциальные сбои форка или команды).

Итоги


Shell-скрипты — это очень удобный инструмент, но при их написании можно допустить массу ошибок. Многие из ошибок, носящих синтаксический характер, которые в других языках обнаружились бы очень быстро, приведя к возникновению сбоя, в нашем случае приводят лишь к тому, что скрипты начинают вести себя неправильно. Последствия неправильного поведения скриптов могут быть практически любыми — от слегка неприятных до катастрофических. Много примеров подобных скриптов можно найти здесь и здесь.

Если в мире есть инструменты для проверки скриптов — почему бы ими не воспользоваться? Даже если (или — даже не «если», а «когда»!) вы редко пишете shell-скрипты, вы можете установить shellcheck, воспользовавшись своим менеджером пакетов, а так же — установить подходящий плагин для своего редактора, вроде Flycheck (Emacs) или Syntastic (Vim) и просто, до определённого момента, обо всём этом забыть.

Когда вы, после установки этих инструментов, будете писать скрипт, редактор автоматически выведет предупреждения и даст советы. Вы можете обращать внимание на сообщения о стилистических погрешностях, а можете и не обращать, но, всё равно, возможно, вам стоит поглядывать на уведомления о неожиданных ошибках и на предупреждения. Это вполне может спасти вашу базу данных.

Совершали ли вы опасные ошибки при написании shell-скриптов?





Комментарии (52):

  1. ALexhha
    /#23039522

    Запускаешь без -eux готовься к неприятностям

  2. unsignedchar
    /#23039816

    Вот что происходит, когда привык к С, а тебя заставляют писать на bash.

    • nullc0de
      /#23039902

      Это не C программист писал, а какой-то PHP гавнокодер. Нормальный кодер сразу видит и понимает потенциальные проблемы кода. Про что статья, я писал практически под каждым постом про shell скрипт, какие проблемы могут возникнуть и как от них защититься. Но тут на хабре действительно больше гавнокодеров, чем думающих и практикующих, и меня тупо заминусовали люди, которые не пишут правильно скрипты. Такое ощущение, что люди никогда даже в глаза официальную документацию не видели.

      • dwdraugr
        /#23040082

        А вы, как я понимаю, полубог, пишущий без ошибок с первого раза?

        • nullc0de
          /#23040174

          dwdraugr причем тут полубог? Бессмертными богами считают себя люди, которые не читают документацию, но с пеной у рта пишут, что bash не безопасный язык программирования и при этом не понимают самых простых вещей. Подобные вещи из unpredictable behavior описываются в документации, и на нормальных курсах по программированию. Даже есть специальные задания на курсах по программированию на тренировку подобных кейсов. Такие вещи есть не только в shell скрипте, а во всех языках. Часто при трудоустройстве в солидную компанию, есть задания на понимание их и вас просто не примут, если вы их не знаете! С опытом такие вещи сразу бросаются в глаза, потому что это не какая-то супер сложная ошибка, а самая простая и детская. Конечно в шараж конторе ушатать сервер может вам сойдет с рук, но если убьете кластер в крупной компании, с вас за убытки могут взыскать очень приличную сумму и трудовую вам напишут не приятную запись, с которой вас почти никуда не возьмут… Да и best practice это использовать shellcheсk.

          • 0xd34df00d
            /#23040386

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

            • nullc0de
              /#23041522

              0xd34df00d, а причем тут haskell? Это не я вам должен по UB говорить, а вы мне, так как вы тут утверждаете, что знаете haskell.

              • 0xd34df00d
                /#23041608

                Вы написали:


                Такие вещи есть не только в shell скрипте, а во всех языках.

                Мой вопрос — это всего лишь частный случай вашего утверждения.

                • nullc0de
                  /#23041654

                  В языках программирования, на которых мне приходилось писать, везде есть UB. Глубоко сомневаюсь, что UB нет в haskell и там нельзя выстрелить себе в ногу.
                  В случае с bash тут безграмотность на лицо и не знание техники безопасности, обработки исключений, и правильного написания кода.

                  Простой пример, вы взяли бензопилу спилить дерево, не зная техники безопасности и правил работы с бензопилой приступили к работе, в итоге бензопила отскочила и отрезала вам ногу, или дерево упало вам на голову. Кто виноват Бензопила!??? Дерево!??? Вы сами? Значит ли это, что бензопила плохая и не безопасная? Подходит ли бензопила выкручивать шурупы? А можете ли вы спилить дерево отверткой?

                  • 0xd34df00d
                    /#23041690 / +1

                    В языках программирования, на которых мне приходилось писать, везде есть UB. Глубоко сомневаюсь, что UB нет в haskell и там нельзя выстрелить себе в ногу.

                    Если упрощать, оно там вылезает тогда, когда вы начинаете лезть в FFI. В повседневной жизни вы с ним не столкнётесь (в отличие от плюсов, где одно формирование указателя дальше, чем past-the-end массива — UB).


                    Простой пример, вы взяли бензопилу спилить дерево, не зная техники безопасности и правил работы с бензопилой приступили к работе, в итоге бензопила отскочила и отрезала вам ногу, или дерево упало вам на голову.

                    А давайте другой пример. Вы с Васей и Петей ехали на машинах (трёх разных) в дождь, все три проехались по луже. У Васи умная машина с ESP, и он поехал дальше, Петю занесло и унесло в кювет, но его спасли подушки безопасности и умно сделанный кузов, сминаемый где надо, а вы убились, потому что у вас в машине ничего этого не было.


                    Здесь кто виноват? Значит ли это, что машина плохая и не безопасная?

                    • nullc0de
                      /#23041728

                      Судя по вашему ответу вы мебель в иномарке кабриолете возите… А мешок картошки только складываете в багажник мерседеса… Это называется «Вася не учился в автошколе, но купил себе феррари и разбился...» Про скоростной режим в дождь ничего не слышали? Чем лучше пилить дерево бензопилой или лобзиком?

                      • 0xd34df00d
                        /#23045234

                        Судя по вашему ответу вы мебель в иномарке кабриолете возите… А мешок картошки только складываете в багажник мерседеса…

                        А вы под каждую такую задачу машину покупаете, что ли, и обязательно без систем безопасности?


                        Это называется «Вася не учился в автошколе, но купил себе феррари и разбился...» Про скоростной режим в дождь ничего не слышали?

                        Про езду со скоростью потока вы что-нибудь слышали?


                        Я как раз вчера ехал как раз в такой дождь (чем и был вдохновлён пример). Стандартное ограничение на дороге — 60 миль в час, народ ехал на 50, несмотря на то, что уже на расстоянии 10 метров нихрена не видно (кроме едва вырисовывающихся габаритных огней, если другой человек не идиот их включил). И я, короче, был очень рад, что у моей машины есть радар, blind spot monitor (для тех идиотов, которые не включили, и которых иначе не видно), эта самая ESP и прочие подобные ништяки.


                        И, кстати, я на ней как раз перевозил некоторую мебель в новое жилище.

      • unsignedchar
        /#23040146

        Может и PHP. Что-то выдавало Штирлица: то ли комментарии через //, то ли уверенность, что при ошибке программа не скомпилируется или хотя бы упадёт… то ли волочащийся сзади парашют :D

        • Hes
          /#23041788

          В Golang комментарии аналогично оформляются

          • nullc0de
            /#23041810

            Hes дело не только в комментариях, в php не любят обрабатывать исключения. В нормальных языках это основа из основ, где-то даже не даст скомпилировать пока исключение не обработаешь. На лицо в скрипте отсутствие обработки исключений. Кто программирует на нормальном языке пытается всегда обработать исключения.

            • tendium
              /#23042670

              в php не любят обрабатывать исключения

              Громкое заявление.

  3. nullc0de
    /#23039942

    Совершали ли вы опасные ошибки при написании shell-скриптов?

    Конечно, не совершает ошибок только тот кто ничего не делает. И сервера удаленные убивал и систему на рабочем компе. Правда было это лет 20 назад. Наверное самые распространенные грабли на которые наступал, это были правила файервола на удаленном сервере.

  4. xakep666
    /#23040004 / +1

    Напомнило историю, как установщик драйверов nvidia по ошибке удалял папку /usr.

  5. maxzhurkin
    /#23040244 / +2

    А по-моему, самым безрассудным было даже не игнорирование возможности проверки линтером, а игнорирование проверок вообще - лично я банально поостерёгся бы использовать подобный скрипт, не проверив его на имитации боевого окружения (ну и линтером бы, конечно, не побрезговал)

    P.S. не знаю, насколько прославлен rm -rf среди программистов, а среди сисадминов - точно

    • divanus
      /#23042298

      rm -rf // вообще первое, подозрительное в скрипте :) что бросилось в глаза сразу :)
      Получился шикарный мем из скрипта :)

  6. scruff
    /#23040468

    Вывод — тестировать все «в песочнице», даже то, что на первый взгляд абсолютно не предвещает беды. Время и ресурсы на песочницу должны быть всегда — пусть хоть древний десктоп на селероне — как минимум; как максимум — среда полностью аналогичная production-у

  7. FlashHaos
    /#23040720 / +2

    Странный кейс описан в статье. Корневая причина заключается в том, что исполнитель просто не знает инструмент, которым решил воспользоваться. Ни одному человеку, который хоть немного писал на шелле, просто в голову не придёт так отмечать комментарии.

    Линтер - это, конечно, симптоматичное решение. Но системно этот вопрос решается по другому. Выше правильно говорили про тестирование, но повторюсь - совершенно не ясно, почему не знающий шелла программист (и не важно, пишет он на Си или ПХП) вообще решал эту задачу.

    • UksusoFF
      /#23040770

      Да даже если и писать коменты, то не понятно зачем на каждую строку.

      • apachik
        /#23040812

        ну мне кажется это вполне нормальная практика, когда слабо владеешь инструментом и раз в год приходится что-то такое написать при помощи гугла на каждую команду.
        Баш скрипты в целом плохо читаются, поэтому для профанов польза явно есть.
        Другой вопрос конечно, почему новичок в баше лазает своими ручонками по серверу с БД-шкой…
        Кстати, перевел гугл транслейтом:

        Временный каталог для файлов резервных копий
        Официальный каталог файлов резервных копий
        Файл резервной копии будет сохранен во время резервного копирования.
        Оператор базы данных
        Пароль оператора базы данных
        Сохраните последнюю резервную копию 14-летней давности
        Формат имен файлов резервных копий
        Создать папку
        Очистите временный каталог
        Создайте эту резервную папку
        Выполнить команду резервного копирования
        Упакуйте файл резервной копии в официальный каталог
        Удалите старый Beizhou 14 дней назад

        • UksusoFF
          /#23040890

          Ну да, но там DB_USER, DB_PASS вроде вполне лаконично и понятно без комментариев.

    • /#23041076

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

  8. rezdm
    /#23040798 / -1

    Из-за опасений подобного подобного я перешёл на концепцию «написать на нормальном языке вместо шелла». Надо по расписанию скопировать чего из фтп, положить в локальную папку и послать письмо — проще наваять на (в зависимости от окружения) чём-то легкопишущемся (сишарп, ява, неважно). Отлаживаемость, поддерживаемость, прдсказуемость, логирование — you name it, намного лучше

    • scrow
      /#23041572

      Человек с другой стороны:

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

      Мой сарказм к тому, что все это лишь инструменты. Да, какой-нибудь новомодный Bosch будет лучше просто молотка. Но бывают моменты, когда нужен именно простой и надежный молоток. А то, что ты можешь им отбить себе палец - уже твои проблемы.
      И подобные рассуждения - уровень джуна, который выучил новую фичу и теперь думает что он познал дзен и все знает.

      • eyudkin
        /#23042160

        А точно ли он будет запускаться везде? К примеру в линуксе и в маке есть одинаковый набор утилит типа grep, sed и тп но с немного разными возможностями и написать скрипт, одинаково работающий и там, и там - как минимум непросто.

      • /#23047792

        Да, какой-нибудь новомодный Bosch

        Начав читать это предложение я уже начал переживать, что новый shell какой-то придумали c интересным названием

        • scrow
          /#23048806

          Ну так давно уже. Bash — Bosch Amazing SHell.

  9. apachik
    /#23040802

    скорее всего скрипт написали и отладили, а в самом конце перед выкладкой решили причесать и добавить комментов…

    • unsignedchar
      /#23040942 / +1

      Причем добавляли комментарии в редакторе без подсветки синтаксиса. Иначе по цвету символов можно догадаться, что с комментариями что то не так.

  10. Loggus66
    /#23040992 / +1

    В скрипте плохо всё.
    — Отсутствие проверок существования каталогов
    — Безусловное выполнение rm -rf вместо выполнения с операндом && (cd dir && rm ...) — при отсутствии директории rm выполнится в текущей
    — Использование rm с wildcard — можно было бы удалять просто OUT_DIR и создавать её в начале скрипта, как и другие каталоги при их отсутствии

    • ZUBR_1
      /#23042638

      ну а еще сам код, DUMP переменная используется только один раз, зачем она там? если можно было бы просто юзать ее значение, переменные рекомендуют писать в виде ${VAR} а не $VAR, вместо `command` для более удобной читаемости я бы использовал $(), значение переменных желательно в "" оформлять, ну и я думал что // это просто шутка, и хз как это вообще баш по синтаксису схавал

  11. sergio_nsk
    /#23041032 / -1

    Не догоняю, как скрипт продолжил выполняться? После третьей строки


    OUT_DIR=/data/backup/mongod/tmp     // ????????

    интерпретатор (zsh) останавливается из-за попытки запуска // с переменной OUT_DIR=/data/backup/mongod/tmp.


    test.sh: 3: test.sh: //: Permission denied

    В bash:


    test.sh: line 3: /: Is a directory

    До запуска rm -rf $OUT_DIR/* с пустой переменной $OUT_DIR не доходит.


    Всё это попахивает выдуманной историей.


    Ссылка на StackOverflow: Deleted database accidentally by a bash script, rescue please

    • up40k
      /#23041348 / +1

      У вас, судя по всему, включен errexit в профиле оболочки, а у китайского разработчика - нет.

      • sergio_nsk
        /#23041474

        Да, всё верно. Я даже не знал, что shell-интерпретатор способен продолжать работать после ненулевого $?.

    • nullc0de
      /#23041508

      sergio_nsk человек про потенциальные проблемы написал, ниже вам правильно ответили.
      По коду сразу понятно, что человек просто не владеет shell скриптом и программирует на другом языке, так не делают люди, которые пишут хорошо скрипты и майтейнерят крупные сервера, программы, и линукс дистрибутивы. Уже не однократно писал на хабре про обработку исключений в shell скриптах, как обычно в скрипте их, отсюда куча проблем. Почему-то в нормальных языках исключения обрабатывают, а в shell про них просто забывают. В shell немного другая логика чем в привычных языках программирования, некоторые вещи с виду и без опыта делаются не удобно и не стоит шуроповертом пытаться забивать гвозди, у bash только одна основная функция автоматизация выполнения команд, куда еще для удобства входят конвеерное выполнение команд и потоковое редактирование. Когда говорят про безопасность bash это такая же ересь, как к примеру сказать, что на R нельзя написать десктоп приложения и синтаксис его не удобен и поэтому язык плохой, там нет безопасности, и он не создан вообще для сложных приложений. Shell скрипт так же как R заточен строго под свои функции и синтаксис их для этого создан. Вы когда нибудь программировали на R?

      Вот примерно как делается правильно:

      pushd "${TAR_DIR:?}" || (
        echo -e "\E[1m\E[31mFailed\E[0m"
        exit 1
      )
      
      rm -fr tmp
      mkdir tmp
      
      popd || (
        echo -e "\E[1m\E[31Failed!\E[0m"
        exit 1
      )
      

  12. dyuriev
    /#23042632 / -1

    #!/bin/bash
    DIR='/';
    cd "$DIR" || exit
    rm -rf ./


    $ shellcheck myscript
    No issues detected!


    эх… таблетка не волшебная

    • ALexhha
      /#23042654 / +1

      и что shellcheck должен был тут сказать? Вполне валидный код. А надо ли вам удалять / или нет — это уже не его забота, имхо

      • dyuriev
        /#23042686

        Тем не менее, shellcheck в прочих случаях ругается на попытку удаления системных директорий, причем проверялось не только на корне, но и на /var, /etc и т.д.

        #!/bin/bash
        rm -rf /


        $ shellcheck myscript

        Line 2:
        rm -rf /
        ^-- SC2114: Warning: deletes a system directory.


        надо ли вам удалять / или нет — это уже не его забота

        То есть все таки предполагается, что его забота

        • tendium
          /#23042706

          Но ведь shellcheck не серебряная пуля. При желании его можно обмануть. Вопрос в том, что его задача не ловить целенаправленные зловреды, а ловить ошибки и недостатки, сделанные незлономеренно. И даже в этом случае, он не может гарантировать отлов вообще всех проблем. Но лучше уж с ним, чем без него.

          • dyuriev
            /#23042732

            С этим не смею спорить.

            Меня смутило высказывание другого комментатора «это не его забота», в то время, когда детектирование удаления системных директорий как раз таки заложено в его функциональность.
            А я же всего лишь указал на то, что инструмент — не панацея.

            • ALexhha
              /#23042766

              А я же всего лишь указал на то, что инструмент — не панацея.
              а разве кто-то утверждал что shellcheck это панацея?

              в то время, когда детектирование удаления системных директорий как раз таки заложено в его функциональность.
              только если оно явное

        • ALexhha
          /#23042730

          Это если у вас идет явное удаление, а если имя директории пользователь вводит с консоли? Или оно получается динамически во время работы скрипта. Это уже немного другая область

  13. ne_zabudka
    /#23044126

    Это как раз мой случай безбэкапнойзаботной юности. Только у меня была опечатка в имени переменной. Как известно для оболочки это не ошибка


    TIPO='/tmp/dir'
    echo ${TIPO}
    rm -rf ${TYPO}/*

    Единственное замечание шелчека — использовать двойные кавычки с переменной.

    • Catwoolfii
      /#23047790

      Странно, у меня вот так получается (Debian 10):

      In backup.sh line 3:
      rm -rf ${TYPO}/*
      ^-- SC2115: Use "${var:?}" to ensure this never expands to /* .
      ^-- SC2153: Possible misspelling: TYPO may not be assigned, but TIPO is.
      ^-- SC2086: Double quote to prevent globbing and word splitting.

      • ne_zabudka
        /#23050074

        Я была не права, не думала что опции могут повлиять на вывод шелчека. Рука не поднялась поставить -rf, оригинал:


        #!/bin/bash
        DIR='/tmp/dir'
        rm -i "${DIRS}"/*
        echo ${DIR}

        Спасибо

        • 776166
          /#23051266

          Обычно tmp не чистят. И вообще, если что-то можно не удалять, не надо удалять, пусть лежит, мало ли. А если лежит, то лежать должно в правильном месте, т.е. в /tmp, которая почистится сама (когда-нибудь).

          • legolegs
            /#23051354

            /tmp чистится при перезагрузке, которая может произойти через годы

          • ne_zabudka
            /#23056808

            Согласна с "обычаями" в готовой программе. Но есть такая вещь как отладка и приходится многократно проверять создание и удалять в ручную или при помощи скрипта.