我已将 Bash 配置为保存带有嵌入换行符的多行历史记录条目。
shopt -s cmdhist lithist
export HISTTIMEFORMAT='%F %T '
当我退出 shell 时,我的历史记录会附加到~/.bash_history
分隔条目的时间戳,例如:
#1501293767
foo() {
echo foo
}
#1501293785
ls
我尝试设置HISTIGNORE
过滤掉一些命令,
HISTIGNORE='ls[ ]*:man[ ]*:cat[ ]*'
但很快意识到我更喜欢将所有内容包含在当前会话的(内存中)历史记录中,我只想过滤写入磁盘以供将来会话的内容。
我想利用杠杆~/.bash_logout
这个过滤功能(我一直在研究这些 答案几个相关的问题)。
多行条目使过滤变得有点复杂。我需要识别时间戳后面的第一行与其中一个可忽略模式匹配的条目,并排除整个条目,包括时间戳。
我想出了一种用 awk 来做到这一点的方法,但是我的 awk 技能不太好,所以我想知道是否有更好的方法?
filter_history() {
tmpfile=$(mktemp)
history -w $tmpfile
awk '/^#[[:digit:]]{10}$/ { timestamp=$0; ignore=0; next }
length(timestamp) > 0 && /^(ls|man|cat)([^[:alnum:]]|$)/ { timestamp=""; ignore=1 ; next }
length(timestamp) > 0 { print timestamp; timestamp=""; print; next }
ignore == 0 { print }' \
$tmpfile >> $HISTFILE && rm $tmpfile
}
编辑:实际上,我想不出我想要过滤掉多行条目的情况。例如,即使它以 开头ls
,如果它跨越多行,它可能正在做一些有趣的事情,并且值得记住。
答案1
即使第一行与“忽略”模式匹配也保留多行条目的要求增加了一些复杂性。我最终在 Awk 中编写了一个有限状态机来在 HISTFILE 写入磁盘后对其进行过滤(在写入之前我找不到触发过滤的方法)。
〜/ .bashrc:
# if shell is interactive, filter history upon exit
if [[ $- == *i* ]]; then
trap '$HOME/.bash_history_filter >/dev/null 2>&1 &' EXIT
fi
〜/ .bash_history_filter:
tmpfile=$(mktemp)
trap 'rm -f "$tmpfile"' EXIT
filter_script="$HOME/.bash_history_filter.awk"
persisted_history="${HISTFILE:-$HOME/.bash_history}"
if [[ -r "$filter_script" && -r "$persisted_history" ]]; then
awk -f "$filter_script" "$persisted_history" > "$tmpfile"
mv "$tmpfile" "$persisted_history"
fi
〜/.bash_history_filter.awk:
/^#[[:digit:]]{10}$/ {
timestamp = $0
histentry = ""
next
}
$1 ~ /^(ls?|man|cat)$/ {
if (! timestamp) {
print
} else {
histentry = $0
}
next
}
timestamp {
print timestamp
timestamp = ""
}
histentry {
print histentry
histentry = ""
}
{ print }
答案2
为了完整起见,以下是我处理 bash 历史记录的方法! (过滤和备份)
不管你是否过滤,HISTFILE对于关心他的历史的人来说是不够的,也不建议使用一个大的HISTFILE,所以肯定有一天你需要将你的历史保存在其他地方!
function shellHist () #find old hist
{
if [[ -f ${HISTFILE}.${1} ]]; then
cat ${HISTFILE}.${1};
else
grep -h "${@:-.}" ${HISTFILE}.*;
fi
}
function shellHistBackup ()
{
[[ -n ${HISTFILE} ]] || return;
# pidKill0 && return; # do nothing if the job is actually running elsewhere
{
while read histLine; do
if ! grep -q "^${histLine}$" ${HISTFILE}.${histLine%% *} 2> /dev/null; then
echo "${histLine}" >> ${HISTFILE}.${histLine%% *};
fi;
done < ${HISTFILE}
for fltr in ls cat any ; do
rm ${HISTFILE}.${fltr}
done
} & # pidLog # related to pidKill0
}
我将 shellHistBackup 包含在“trap shellExit EXIT”中
我希望这对某人有用!