Como remover todas as entradas contendo uma string específica do comando histórico no BASH?

Como remover todas as entradas contendo uma string específica do comando histórico no BASH?

Existe algum comando ou maneira de remover todas as entradas do histórico do shell bash contendo uma string específica? isso será útil para remover comandos do histórico contendo senha. Eu sei que podemos remover cada entrada do histórico pelo seu número, mas o problema é que ela exclui apenas uma entrada por vez e preciso retirar o número a cada vez para remover uma nova entrada.

por exemplo. O comando histórico mostra 5 entradas contendo a senha abcabc e quero remover todas as entradas do comando histórico contendo a string abcabc

975  2019-03-15 11:20:30 ll
  976  2019-03-15 11:20:33 ll cd
  977  2019-03-15 11:20:36 ll CD
  978  2019-03-15 11:20:45 chown test1:test1 CD
  979  2019-03-15 11:20:53 chown test1:test1 ./CD
  980  2019-03-15 11:20:57 chown test1:test1 .\CD
  981  2019-03-15 11:22:04 cd /tmp/logs/
  982  2019-06-07 10:36:33 su test1
  983  2019-08-22 08:35:10 su user1
  984  2019-08-22 08:35:15 /opt/abc/legacy.exe -password abcabc
  985  2019-09-24 07:20:45 cd /opt/test1/v6r2017x
  986  2019-09-24 07:20:46 ll
  987  2019-09-24 07:21:18 cd /tmp/
  988  2019-09-24 07:21:19 ll
  989  2019-09-24 07:21:24 cd linux_a64/
  990  2019-09-24 07:21:25 /opt/abc/legacy.exe -password abcabc
  991  2019-09-24 07:24:03 cd  build/
  992  2019-09-24 07:24:04 ll
  993  2019-09-24 07:24:07 cd ..
  994  2019-09-24 07:24:10 /opt/abc/legacy.exe -password abcabc
  995  2019-09-24 07:24:15 cd someapp/bin
  996  2019-09-24 07:24:21 ll
  997  2019-09-24 07:24:33 cd .
  998  2019-09-24 07:24:35 cd ..
  999  2019-09-24 07:24:36 ll

Tentei seguir o comando que deu o erro conforme indicado abaixo

servername:~ # sed -i 'g/abcabc/d' /home/user1/.bash_history
sed: -e expression #1, char 2: extra characters after command

Expectativa: Nenhum erro e todas as entradas contendo a string abcabc devem ser removidas.

Responder1

Outra semelhante à resposta do @cprn, mas usando awk(em vez de cut) e uma função:

function del_word_history () {
  if [ -z "${1}" ]; then return false; fi
  mapfile -t result <<< "$(history | grep "${1}" | tac | awk '{print $1}')"
  for idx in "${result[@]}"; do
    history -d $idx
  done
}
  • tacinverte as linhas da saída (alguns posts apontaram que não é comum a todos os sistemas)
  • [-z $1 ]: truese o primeiro argumento passado para a função ( $1) estiver vazio.
  • mapfile -t(página de manual;alguns guias): lê stdinem uma variável de array ( result)
    • "${result[@]}"retorna a matriz
  • awk '{print $1}'(Guia do usuário GNU,breves guias,página de manual): usado para ambos: identificar uma correspondência e processá-la. Ele divide os dados delimitados por espaços em branco (padrão) e os armazena nas $nvariáveis.
  • '{pring $1}'lê paraexecutar printação na primeira palavra.

Uso:

del_word_history history
del_word_history abcabc
history -w

O abaixo é umsolução mais limpaque verifica se obtivemos o idxnúmero de history, em vez de alguma outra palavra de uma entrada multilinha:

function del_word_history () {
  if [ -z "${1}" ]; then return false; fi
  mapfile -t lines <<< "$(history | grep "${1}" | tac)"
  for line in "${lines[@]}"; do
    idx="$(printf '%s' "${line}" | awk '{ if ($1 ~ /^[0-9]+$/) { print $1 } }')"
    if [ -n "${idx}" ]; then
      echo "removing line ${idx}"
      history -d $idx
    fi
  done
}

As principais diferenças são:

  • obtemos as linhas completas na variável array linesviamapfile
  • awk '{ if ($1 ~ /^[0-9]+$/) { print $1 }}'verifica se a primeira palavra de cada linha é um número e é stdouta mesma primeira palavra (e chega à idxvariável)
  • [ -n ${idx}" ] just checks ifidx` não está vazio

Responder2

Eu sei que é antigo, mas fiz isso em um loop assim:

for ln in $( history | grep my_phrase | cut -f2 -d' '); do
    history -d $ln
done
  • $(...)- substituição de comando, retornos stdoutde...
  • cut -f2 -d' '- corta a segunda coluna da saída delimitada por espaço, ou seja, número da linha
  • history -d $ln- remove determinado número de linha do histórico

Um forro para fácil copiar e colar:

for ln in $( history | grep my_phrase | cut -f2 -d' '); do history -d $ln; done

Responder3

você pode usar sedpara remover entradas de .bash_history.
Mas como é uma senha para evitar digitá-la novamente na CLI, aconselho você a editar seu .bashrcarquivo e garantir que a linha with HISTCONTROLesteja definida como ignorebothou ignorespace. Isso permitiria que você digitasse o comando bashe não os colocasse no histórico se eles começassem com um espaço:

promtpt:$ sed -i '/abcabc/d' /home/user/.bash_history

Observe o espaço entre $e o comando, isso faria com que a linha fosse ignorada no histórico do bash.

-i: significa editar arquivo embutido.
dno final significa remover a linha contendo a expressão entre /.

Esta solução só funciona em Linux GNU sed.

informação relacionada