Как удалить все записи, содержащие определенную строку, из истории команд в BASH?

Как удалить все записи, содержащие определенную строку, из истории команд в BASH?

Есть ли какая-либо команда или способ удалить все записи из истории оболочки bash, содержащие определенную строку? Это будет полезно для удаления команд из истории, содержащих пароль. Я знаю, что мы можем удалить каждую запись истории по ее номеру, но проблема в том, что она удаляет только одну запись за раз, и мне нужно каждый раз выводить номер, чтобы удалить новую запись.

например. Команда History показывает 5 записей, содержащих пароль abcabc, и я хочу удалить все записи из команды History, содержащие строку 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

Попробовал следующую команду, которая выдала ошибку, как указано ниже

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

Ожидание: ошибок не возникнет, и все записи, содержащие строку abcabc, должны быть удалены.

решение1

Еще один ответ, похожий на ответ @cprn, но с использованием awk(вместо cut) и функции:

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
}
  • tacинвертирует строки вывода (в некоторых сообщениях указывалось, что это не свойственно всем системам)
  • [-z $1 ]: trueесли первый аргумент, переданный функции ( $1), пуст.
  • mapfile -t(страница руководства;некоторые гиды): считывает stdinв переменную массива ( result)
    • "${result[@]}"возвращает массив
  • awk '{print $1}'(Руководство пользователя GNU,краткие руководства,страница руководства): используется для обоих: определения совпадения и его обработки. Он разделяет данные, разделенные пробелами (по умолчанию), и сохраняет их в $nпеременных.
  • '{pring $1}'читает длявыполнить printдействие над первым словом.

Использование:

del_word_history history
del_word_history abcabc
history -w

Ниже представленоболее чистое решениекоторый проверяет, получили ли мы номер idx, historyа не какое-либо другое слово многострочной записи:

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
}

Основные отличия:

  • мы получаем полные строки в переменной массива linesчерезmapfile
  • awk '{ if ($1 ~ /^[0-9]+$/) { print $1 }}'проверяет, что первое слово каждой строки является числом, и это stdoutто же самое первое слово (и попадает в idxпеременную)
  • [ -n ${idx}" ] just checks ifidx` не пуст

решение2

Я знаю, что это старо, но я просто сделал это в цикле, вот так:

for ln in $( history | grep my_phrase | cut -f2 -d' '); do
    history -d $ln
done
  • $(...)- замена команд, stdoutвозвраты...
  • cut -f2 -d' '- вырезает 2-й столбец разделенного пробелом вывода, т.е. номер строки
  • history -d $ln- удаляет указанный номер строки из истории

Одна строка для легкого копирования и вставки:

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

решение3

вы могли бы использовать sedдля удаления записей из .bash_history.
Но так как это пароль, чтобы избежать повторного ввода пароля в CLI, я бы посоветовал вам отредактировать ваш .bashrcфайл и убедиться, что строка с HISTCONTROLустановлена ​​на ignorebothили ignorespace. Это позволит вам вводить команду bashи не помещать их в историю, если они начинаются с пробела:

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

Обратите внимание на пробел между $и командой, это приведет к тому, что строка будет проигнорирована в истории bash.

-i: означает редактирование файла в строке.
dВ конце означает удаление строки, содержащей выражение между /.

Это решение работает только на Linux GNU sed.

Связанный контент