Запретить выполнение команды после другой команды

Запретить выполнение команды после другой команды

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

Как предотвратить cmd2выполнение команды после cmd1.

Например:

$ tar tf file.tar
$ rm !$

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

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

решение1

В bash вы можете установить shopt -s histverify, что остановит историю от расширения и выполнения за один шаг. Здесь вышеприведенное $ rm !$будет расширяться до $ rm file.tarпри первом нажатии Enter, позволяя вам проверить или отредактировать перед Enterповторным нажатием для выполнения.
Более общее решение будет сворачивать в«Делай то, что я имею в виду»территория, требующая от программы переосмысления ваших намерений.

решение2

Вы просите слишком многого, давая общий ответ, но в какой-то степени это должно быть относительно легко сделать.

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

$ PROMPT_COMMAND='echo BOFH says hi!'
BOFH says hi!
$ man man
BOFH says hi!
$

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

$ PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
PROMPT_COMMAND='history -a; tail -n1 ~/.bash_history'
$ wc < test.sh | grep .
 5 11 63
wc < test.sh | grep .

Теперь наступает очередь логики, которая полностью зависит от вас. Давайте воспользуемся очень упрощенной логикой, чтобы предотвратить пример в вопросе. Важно помнить, что функции bash все еще работают, поэтому вам не нужно втискивать все в одну строку, в одну переменную.

$ # define the logic check
$ checkSanity() { grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
checkSanity() { grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$@" && echo "be careful, don't delete this"; }
$ # feed it the last command
$ PROMPT_COMMAND='history -a; last=$(tail -n1 ~/.bash_history); checkSanity "$last"'
$ # simple test
$ tar tf test.sh 2>/dev/null 
be careful, don't delete this
$ tar xf test.sh 2>/dev/null 
$

Конечно, этот подход полезен для предотвращения PEBKAC (особенно если вы добавляете его sleep 3в конце), но он не может сам по себе нарушить выполнение следующей команды.

Если это такДействительното, что вы хотите, перехватите DEBUGсигнал (например, trap 'echo "I am not deterministic, haha"' DEBUG), так как он запускается заранее. Будьте осторожны с объединением этих двух подходов, так как выход/действие будут дублироваться:

$ df
/.../
$ trap 'tail -n1 ~/.bash_history' DEBUG
df
df
trap 'tail -n1 ~/.bash_history' DEBUG
trap 'tail -n1 ~/.bash_history' DEBUG

Чтобы ловушка прервала команду, вам нужно включить extdebug( shopt -s extdebug). Вам также не нужно постоянно сохранять и перечитывать историю, но вы можете проверить, $BASH_COMMANDчтобы команда была готова к запуску. Затем вам просто нужно убедиться, что логическая проверка возвращает 1, когда она обнаруживает что-то плохое, и 0 в противном случае.

          extdebug
                  If set, behavior intended for use by debuggers is enabled:
    /.../
                  2.     If  the command run by the DEBUG trap returns a non-zero value, the next
                         command is skipped and not executed.


$ checkSanity() { if grep -q "tar  *[tf][[:alpha:]]*[tf] " <<< "$1"; then  echo "be careful, don't delete this"; return 1; fi; }
$ trap 'checkSanity "$BASH_COMMAND"' DEBUG
$ # simple test
$ tar tf test.sh 2>/dev/null 
be careful, don't delete this
$ tar xf test.sh 2>/dev/null 
$

решение3

В этом случае вам пригодятся предупреждения об ошибках от rmкоманды.

В скриптах инициализации оболочки (предполагая bash, что , поэтому ~/.bashrc) вы можете использовать псевдонимы rmлибо -i, либо -I.

alias rm="rm -i"

Отman 1 rm

   -i     prompt before every removal

   -I     prompt once before removing more than three files, or when
          removing recursively.  Less intrusive than -i, while still
          giving protection against most mistakes

Более общий вопрос: «Как мне защитить свою систему от меня самого?»обсуждалось ранее. В двух словах,обратите внимание на то, что вы делаетеи запускайте команды только rootпри необходимости.

решение4

В вашем конкретном случае я бы сделал следующее:

tar tf file.tar
if [ -f file ]; then   # Assuming you meant to extract a file
  rm -f file.tar
else
  echo "file is missing. Command failed."
fi

Если вы хотите проверить наличие ошибок и выполнить следующую команду только в случае успешного выполнения первой

some_command && another_command

Хотя в вашем конкретном случае вторая команда все равно будет выполнена, поскольку не выдаст ошибку, даже если она не сделает то, что вы хотели.

Связанный контент