bash_history:危険なコマンドコメント処理: `#

bash_history:危険なコマンドコメント処理: `#

「危険な」コマンドがbash履歴に書き込まれるのを防ぐために、ファイルに次の行を追加しました.bashrc

HISTIGNORE='rm *:mv *:cp *:cat*>*:pv*>*'

これはうまく機能しますが、副作用があります。コンピュータで実行されたコマンドの完全な履歴を表示できません。実験用コンピュータがいくつかあり、実行されているすべてのコマンドを表示できるようにしたいとします。 bashの内部を使用してhistory実行されたコマンドを表示し、grepを使用して今日の日付を表示することもできます。

history | grep Sep-28

私がしたいのは、「危険な」コマンドも記録しますが、誤ってレコード#からコマンドを実行しても破損が発生しないように、行の先頭に1つを入れることです。

これが可能かどうかわかりません。

アップデートと説明:

これが私にとって問題となる主な理由は、通常、複数の端末から自分のコンピュータに接続し、ある端末で実行されたすべてのコマンドがすぐに別の端末の履歴に読み込まれるためです。これは以下によって達成される。

PROMPT_COMMAND="history -a; history -c; history -r"

2つの端末が開いているとしましょう。そのうちの1つでcat /dev/foo > file.outいくつかのプロセスを実行しています。 2番目のステップでは、チェックの進行状況を使用しますls -lAhF。 and(つまり、履歴の最後のコマンド)をls押して繰り返し続けます。最初のコマンドが完了すると、記録の最後のコマンドではなくなります。注意しない場合は、catを再起動してfile.outを上書きします。UpENTERlscat /dev/foo > file.out

#私が達成したいのは、実行されないようにcatコマンドの前にaを置くことです。ただし、履歴にはまだ表示され、コメントを削除して再利用できます(長いコマンドの場合)。

答え1

あなたの質問に正確に答えることはありませんが、あなたの問題に対する代替ソリューションを提供することもできます。

私が正しく理解した場合は、入力中に発生する可能性がある間違いを心配しています。たとえば、履歴の前のコマンドが保持したい項目を削除した!rm場合です。rm

この場合は良い強く打つオプションはですhistverifyshopt -s histverifybangでコマンドを呼び出すと、!すぐには実行されずにreadlineにロードされ、実行するかどうかを判断でき、編集も可能です。

試してみてください:

  • いいえhistverify:

    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    rm some_foo
    $ # oooops in fact I'd've like to keep it this time
    
  • そしてhistverify

    $ shopt -s histverify
    $ touch some_foo
    $ rm some_foo
    $ touch some_foo
    $ !rm
    $ rm some_foo <cursor here>
    

    この場合、カーソルは行の末尾にあり、再起動または編集できます。

このオプションが好きな場合は、次の項目に入力してください.bashrc

shopt -s histverify

答え2

次のことができます。

fixhist() {
   local cmd histnum
   cmd=$(HISTTIMEFORMAT=/ history 1)
   histnum=$((${cmd%%[*/]*}))
   cmd=${cmd#*/} # remove the histnum
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -s "#$cmd"    # add back with a #
   esac
}
PROMPT_COMMAND=fixhist

アイデアは、各プロンプトの前に最後の履歴エントリ(history 1)とそれが次のいずれかであるかどうかを確認することです。危険、我々はそれを削除し(history -d#として再度追加しますhistory -s

(もちろん設定を削除する必要がありますHISTIGNORE。)

しかし、望ましくない副作用の1つはそれが変わるということです。歴史的な時間その中には…命令がrmありますmv

この問題を解決するための代替案は次のとおりです。

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       HISTFILE=/dev/stdin history -r <<EOF
#$time
#$cmd
EOF
   esac
}
PROMPT_COMMAND=fixhist

今回は、最後の履歴項目の時刻を記録し、履歴行を再度追加します。history -rタイムスタンプを含む一時ファイルを使用します(ここで説明されています)。

fixhistあなたはあなたの前に実行したいと思いますhistory -a; history -c; history -r。残念ながら、現在のバージョンには追加した行が追加されないbashバグがあります。history -a解決策は次のように書くことです。

fixhist() {
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time=${cmd%%>*}
   time=${time#*<}
   cmd=${cmd#*>}
   case $cmd in
     (rm\ *|mv\ *|...)
       history -d "$histnum" # delete
       history -a
       [ -f "$HISTFILE" ] && printf '#%s\n' "$time" "$cmd" >> "$HISTFILE";;
     (*)
       history -a
   esac
   history -c
   history -r
}
PROMPT_COMMAND=fixhist

つまり、コメント化されたコマンドをHISTFILEがhistory -a実行するのではなく、直接HISTFILEに追加します。

答え3

これステファンの答えを受け入れました。本当にすごい。私が採用した方法は次のとおりです。パターンマッチングが若干異なります。

if代わりにステートメントを使用すると、case正規表現マッチング()を使用でき、[[ "$cmd" =~ <REGEX> ]]以下のコードは次のロジックで動作します。

  • 次の場合は、履歴に追加しないでください。
    • コマンドラインは、2つ以上の連続するスペースで始まるか終了します。
      例:
      • <spc><spc>history
  • 次の場合にコメント付きのコマンドを追加します。
    • rmまたはmvcliスイッチでコマンド
    • コマンドラインは:;1つのスペースで始まるか、;:
      次に終わります。例:
    • rm -R /tmp/somedir

    • echo "doing something dangerous I don't want to trip by accident";:

      これにはキャビアも含まれていますが、例えば次のようになります。

    • echo ";rm -something"

  • それ以外の場合は、レコードに追加の
    例:
    • rm somefile
    • echo ";rm -something"

パスワード

_history_hook() {
# The code below is from https://unix.stackexchange.com/a/110056/138012
# history builtiun options used:  https://www.gnu.org/software/bash/manual/html_node/Bash-History-Builtins.html
# history -a : Append new (mem) lines to history (file)
# history -d : Delete range (mem)
# history -c : Clear history list (mem) ++
# history -r : Read (file) append to (mem) ++
# ++ needed to circumvent a bug issue.
   local cmd time histnum
   cmd=$(HISTTIMEFORMAT='<%s>' history 1)
   histnum=$((${cmd%%[<*]*}))
   time="${cmd%%>*}"
   time=${time#*<}
   cmd="${cmd#*>}"
   # different behaviors for different patterns
   if [[ "$cmd" =~ ^\ \ +.*|\ +\ $ ]]; then
   # delete only (two spaces - leading or trailing)
       history -d "$histnum" # delete
   elif [[ "$cmd" =~ ((^|;[[:space:]]*)(rm|mv)\ +-)|^\ |^:\;|\;:$ ]]; then
   # rewrite history as a 'safe version'
       history -d "$histnum" # delete
       history -a
       [ -f "$HISTFILE" ] && printf '# %s\n' "$time" "$cmd" >> "$HISTFILE"
   else
   # append 'as usual'
       history -a
   fi
   # rewriting history file
   history -c
   history -r
}

export HISTCONTROL=erasedups # This does not seem to work right now - need to fix this
export PROMPT_COMMAND="$PROMPT_COMMAND; _history_hook"

関連情報