「危険な」コマンドが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を上書きします。UpENTERls
cat /dev/foo > file.out
#
私が達成したいのは、実行されないようにcatコマンドの前にaを置くことです。ただし、履歴にはまだ表示され、コメントを削除して再利用できます(長いコマンドの場合)。
答え1
あなたの質問に正確に答えることはありませんが、あなたの問題に対する代替ソリューションを提供することもできます。
私が正しく理解した場合は、入力中に発生する可能性がある間違いを心配しています。たとえば、履歴の前のコマンドが保持したい項目を削除した!rm
場合です。rm
この場合は良い強く打つオプションはですhistverify
。shopt -s histverify
bangでコマンドを呼び出すと、!
すぐには実行されずに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
- コマンドラインは、2つ以上の連続するスペースで始まるか終了します。
- 次の場合にコメント付きのコマンドを追加します。
rm
またはmv
cliスイッチでコマンド- コマンドラインは
:;
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"