로그아웃 시 여러 줄의 Bash 기록에서 특정 명령을 필터링하는 방법은 무엇입니까?

로그아웃 시 여러 줄의 Bash 기록에서 특정 명령을 필터링하는 방법은 무엇입니까?

개행이 포함된 여러 줄 기록 항목을 저장하도록 Bash를 구성했습니다.

shopt -s cmdhist lithist
export HISTTIMEFORMAT='%F %T '

셸을 종료하면 내 기록에 ~/.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

첫 번째 줄이 "무시" 패턴과 일치하더라도 여러 줄 항목을 유지해야 한다는 요구 사항으로 인해 약간의 복잡성이 추가됩니다. 나는 HISTFILE이 디스크에 기록된 후 이를 필터링하기 위해 Awk에 유한 상태 머신을 작성하게 되었습니다(기록되기 전에 필터링을 트리거하는 방법을 찾을 수 없었습니다).

~/.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 }

일부 관련 게시물(여기그리고여기) 이것이 sed를 사용하여 수행될 수도 있다고 의심됩니다. 아직 알아보진 못했지만 비교해서 어떤지 알고 싶습니다.

답변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
}

"trap shellExit EXIT"에 shellHistBackup을 포함합니다.

이것이 누군가에게 유용하길 바랍니다!

관련 정보