Como posso filtrar certos comandos do histórico de várias linhas do Bash no logout?

2

Configurei o Bash para salvar entradas de histórico de múltiplas linhas com novas linhas incorporadas.

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

Quando saio do shell, meu histórico é anexado a ~/.bash_history com carimbos de data e hora que separam as entradas, como:

#1501293767
foo() {
echo foo
}
#1501293785
ls

Eu experimentei configurar HISTIGNORE para filtrar alguns comandos,

HISTIGNORE='ls[ ]*:man[ ]*:cat[ ]*'

mas rapidamente percebi que prefiro incluir tudo na história da sessão atual (na memória), só quero filtrar o que é gravado no disco para sessões futuras.

Gostaria de aproveitar ~/.bash_logout para fazer essa filtragem (estou pesquisando esses responde a algumas perguntas relacionadas).

As entradas de múltiplas linhas tornam a filtragem um pouco complicada. Eu preciso identificar entradas em que a primeira linha após o registro de data e hora corresponda a um dos padrões ignoráveis e exclua toda a entrada, incluindo o registro de data e hora.

Eu criei uma maneira de fazer isso com o awk, mas minhas habilidades no awk não são ótimas, então eu me pergunto se existe uma maneira melhor?

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
}

Editar : Na verdade, não consigo pensar em um caso em que eu queira filtrar uma entrada de várias linhas. Mesmo que comece com ls , por exemplo, se ele ocupar várias linhas, provavelmente está fazendo algo interessante e vale a pena lembrar.

    
por ivan 29.07.2017 / 06:59

2 respostas

1

O requisito para manter entradas de várias linhas, mesmo se a primeira linha corresponder a um padrão "ignorar", adicionou alguma complexidade. Acabei escrevendo uma máquina de estado finito no Awk para filtrar HISTFILE depois que ela foi gravada no disco (não consegui encontrar uma maneira de acionar a filtragem antes que ela já tivesse sido gravada).

~ / .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=$0histentry=""
  next
}
$1 ~ /^(ls?|man|cat)$/ {
  if (! timestamp) {
    print
  } else {
    histentry = $0
  }
  next
}
timestamp {
  print timestamp
  timestamp = ""
}
histentry {
  print histentry
  histentry = ""
}
{ print }

Algumas postagens relacionadas ( aqui e aqui ) me levam a suspeitar que isso também pode ser feito usando sed. Eu ainda não percebi isso, mas eu ficaria curioso para ver como isso é comparado.

    
por 30.07.2017 / 05:15
0

para a completude, aqui está como eu lido com a história do bash! (filtrar e fazer backup)

mas você filtra ou não o HISTFILE não é bom para alguém que se preocupa com sua história, também ter um HISTFILE grande não é recomendado, então com certeza algum dia você precisará manter sua história em outro lugar!

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
}

eu incluo shellHistBackup em "trap shellExit EXIT"

espero que isso seja útil para alguém!

    
por 31.07.2017 / 16:52