コマンドが別のコマンドの後に実行されないようにする

コマンドが別のコマンドの後に実行されないようにする

これから起こりそうなエラーについてシェルが警告してくれるようにしたいです。

の後にコマンドがcmd2実行されないようにするにはどうすればよいですかcmd1

例えば:

$ tar tf file.tar
$ rm !$

ここでは、ファイルの内容を抽出するのではなく、ファイルをリストしたことを忘れていました。

前のコマンドの名前と戻り値、および現在のコマンドに基づいて選択を行う汎用的なソリューションを探しています。

答え1

bashでは、 を設定するshopt -s histverifyことで、履歴の展開と実行を1ステップで停止できます。ここでは、 を最初に押すと$ rm !$に展開され、もう一度押して実行する前に確認または編集できます。 より一般的な解決策は、$ rm file.tarEnterEnter
「私の意図通りにやれ」プログラムがあなたの意図を推測する必要がある領域です。

答え2

一般的な答えでは多くのことを要求していますが、ある程度は比較的簡単に実行できるはずです。

ただし、bashこの問題を解決するのに役立つ一般的なメカニズムが少なくとも 2 つあります。変数 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 関数はそこでも機能するため、すべてを 1 行、1 つの変数に詰め込む必要がないということです。

$ # 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) をトラップすることです。出力/アクションが 2 倍になるため、これら 2 つのアプローチを組み合わせる場合は注意してください。

$ 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

ただし、あなたの特定のケースでは、2 番目のコマンドは、期待どおりに動作しなかったにもかかわらず、エラーが発生しなかったため、引き続き実行されます。

関連情報