.bash_history에서 중복을 제거하고 순서를 유지하려면 어떻게해야합니까?


60

나는 control+r내 명령 기록을 재귀 적으로 검색하기 위해 사용 하는 것을 정말로 좋아 합니다. 함께 사용하기에 좋은 몇 가지 옵션을 찾았습니다.

# ignore duplicate commands, ignore commands starting with a space
export HISTCONTROL=erasedups:ignorespace

# keep the last 5000 entries
export HISTSIZE=5000

# append to the history instead of overwriting (good for multiple connections)
shopt -s histappend

나에게 유일한 문제는 erasedups순차적 복제 만 지우는 것이므로이 명령 문자열을 사용하면됩니다.

ls
cd ~
ls

ls명령은 실제로 두 번 기록됩니다. 나는 cron을 주기적으로 실행하는 것에 대해 생각했습니다.

cat .bash_history | sort | uniq > temp.txt
mv temp.txt .bash_history

이렇게하면 복제본을 제거 할 수 있지만 불행히도 순서는 유지되지 않습니다. 내가하지 않으면 sort파일을 처음 나는 생각하지 않는다 uniq제대로 작동 할 수 있습니다.

.bash_history에서 중복을 제거하고 순서를 유지하려면 어떻게해야합니까?

추가 크레딧 :

.bash_history스크립트를 통해 파일을 덮어 쓰는 데 문제가 있습니까? 예를 들어, 아파치 로그 파일을 제거하면 파일에 kill연결하기 위해 nohup / reset 신호를 보내야한다고 생각 합니다. .bash_history파일 의 경우 ps필터링 스크립트를 실행하기 전에 연결된 세션이 없는지 확인하고 확인 하는 데 사용할 수 있습니까?


3
시도 ignoredups대신 erasedups잠시 동안 그 당신을 위해 작동하는 방법을 참조하십시오.
— jw013

1
bash는 히스토리 파일에 열린 파일 핸들을 가지고 있다고 생각하지 않습니다. 필요할 때 읽거나 씁니다. 따라서 다른 곳에서 덮어 쓸 수 있어야 합니다 (참고- 테스트하지 않아야합니다).
— D_Bye

1
방금 질문의 첫 문장에서 새로운 것을 배웠습니다. 좋은 트릭!
— Ricardo

history명령에 대한 모든 옵션에 대한 매뉴얼 페이지를 찾지 못했습니다 . 어디서 볼까?
— Jonathan Hartley

히스토리 옵션은 'man bash'에서 'shell builtin commands'섹션을 찾은 다음 그 아래의 'history'를 검색하십시오.
— Jonathan Hartley

답변:


36

역사 정렬

이 명령은처럼 작동 sort|uniq하지만 줄을 그대로 유지합니다

nl|sort -k 2|uniq -f 1|sort -n|cut -f 2

기본적으로 각 줄 앞에 숫자가 붙습니다. sort|uniq-ing 후 , 모든 행은 원래 순서에 따라 정렬되며 (행 번호 필드 사용) 행 번호 필드는 행에서 제거됩니다.

이 솔루션에는 정의 된 동일한 라인 클래스를 나타내는 결과가 출력에서 ​​만들어 지므로 최종 출력에서의 위치가 정의되지 않은 결함이 있습니다. 그러나 최신 담당자를 선택해야 할 sort경우 두 번째 키로 입력 할 수 있습니다 .

nl|sort -k2 -k 1,1nr|uniq -f1|sort -n|cut -f2

.bash_history 관리

다시 읽기와 역사를 다시 쓰기 위해, 당신은 사용할 수 있습니다 history -a및 history -w각각.


6
쉘 도구로 구현 된 decorate-sort-undecorate 버전 . 좋은.
— ire_and_curses

으로 sort의 -r스위치는 항상 정렬 순서를 반전시킵니다. 그러나 이것은 당신이 생각한 결과를 얻지 못할 것입니다. sort는 ls반대의 경우에도 결과 순서가 정렬 알고리즘에 따라 달라지는 결과와 동일한 것으로 간주 됩니다. 그러나 다른 아이디어에 대한 내 업데이트를 참조하십시오.
— artistoex

1
.bash_history를 수정하지 않으려는 경우 .bashrc에 다음을 넣을 수 있습니다. alias history = 'history | 정렬 -k2 -k 1,1nr | uniq -f 1 | sort -n '
— Nathan

nl각 코드 줄의 시작 부분은 무엇입니까 ? 그렇지 history않습니까?
— AL

1
@AL nl은 줄 번호를 추가합니다. 이 명령은 전체적으로 일반적인 문제를 해결합니다. 순서를 유지하면서 복제본을 제거합니다. 입력은 stdin에서 읽습니다.
— artistoex

48

그래서 나는 중복에 의해 성가신 후 똑같은 것을 찾고 있었고 ~ / .bash_profile (Mac)을 다음과 같이 편집하면 :

export HISTCONTROL=ignoreboth:erasedups

정확히 원하는 것을 수행하고 최신 명령 만 유지합니다. ignoreboth실제로하는 것과 같습니다. ignorespace:ignoredups그와 함께 erasedups작업을 수행합니다.

적어도 내 맥 터미널에서 bash가 완벽하게 작동합니다. 여기 askubuntu.com 에서 찾았습니다 .


10
정답이어야합니다.
— MitchBroadhead

Max OS X Yosemite 및 Ubuntu 14_04에서 테스트
— Ricardo

1
@MitchBroadhead에 동의하십시오. 이것은 외부 크론 작업없이 bash 자체의 문제를 해결합니다. 우분투 17.04 및 16.04 LTS에서 테스트
— Georg Jung

OpenBSD에서도 작동합니다. 기록 파일에 추가하는 명령의 딥 만 제거합니다. 이전에 중복으로 존재했던 명령을 입력 할 때 히스토리 파일을 단축시키는 흥미로운 효과가 있습니다. 이제 히스토리 파일을 최대로 짧게 만들 수 있습니다.
— WeakPointer

1
중복 된 연속 명령 만 무시합니다. 당신은 주어진 두 개의 명령 사이에 반복적으로 번갈아 경우, bash는 역사는 중복으로 채울 것
— Dylanthepiguy

16

이 솔루션을 야생에서 발견하고 테스트했습니다.

awk '!x[$0]++'

라인의 특정 값 ($ 0)을 처음 볼 때 x [$ 0]의 값은 0입니다.
0의 값은 거꾸로되어 !1이됩니다.
1로 평가되는 명령문은 기본 조치 (인쇄)를 유발합니다.

따라서 특정 내용을 처음 $0볼 때 인쇄됩니다.

다음에 (반복 할 때마다) 값 x[$0]이 오름차순이고
, 부정 된 값은 0이며, 0으로 평가되는 명령문은 인쇄되지 않습니다.

마지막으로 반복되는 값을 유지하려면 기록을 되돌리고 동일한 awk를 사용하십시오.

awk '!x[$0]++' ~/.bash_history                 # keep the first value repeated.

tac ~/.bash_history | awk '!x[$0]++' | tac     # keep the last.

와! 방금 효과가있었습니다. 그러나 그것은 내가 생각하는 첫 번째 사건을 제외한 모든 것을 제거합니다. 이것을 실행하기 전에 Sublime Text를 사용하여 줄 순서를 반대로 바꿨습니다. 이제 남은 모든 복제본의 마지막 항목만으로 깨끗한 기록을 얻기 위해 다시 되돌릴 것입니다. 감사합니다.
— trss

내 대답을 확인하십시오!
— 알리 Shakiba

bazilion 하위 프로세스를 시작하지 않고 깨끗하고 일반적인 답변 (역사 사용 사례에 국한되지 않음) ;-)
— JepZ

9

Clayton 답변 연장 :

tac $HISTFILE | awk '!x[$0]++' | tac | sponge $HISTFILE

tac당신이 설치되어 있는지 확인, 파일을 역 moreutils당신이 그래서 sponge그렇지 않으면 임시 파일을 사용 가능합니다.


1
Mac 사용자의 brew install coreutils경우을 사용 하고 모든 GNU utils에는 gBSD 내장 Mac 명령과의 혼동을 피하기 위해 접두사가 붙습니다 (예 : gsed는 GNU, sed는 BSD). 따라서 사용하십시오 gtac.
— tralston

나는 역사를 사용하기 위해 역사 -c와 역사 -r이 필요했다
— drescherjm

4

이것들은 마지막으로 복제 된 줄을 유지합니다.

ruby -i -e 'puts readlines.reverse.uniq.reverse' ~/.bash_history
tac ~/.bash_history | awk '!a[$0]++' | tac > t; mv t ~/.bash_history

명시 적으로, 여기에 두 개의 (화려한) 솔루션을 표시했으며 사용자가 그 중 하나만 실행하면된다는 것을 이해하고 있습니까? 루비 또는 배쉬 중 하나입니까?
— Jonathan Hartley

3

이 게시물은 오래된 게시물이지만 여러 터미널을 열어두고 내역을 창 사이에 동기화했지만 복제하지 않은 사용자에게는 영원한 문제입니다.

.bashrc의 내 솔루션 :

shopt -s histappend
export HISTCONTROL=ignoreboth:erasedups
export PROMPT_COMMAND="history -n; history -w; history -c; history -r"
tac "$HISTFILE" | awk '!x[$0]++' > /tmp/tmpfile  &&
                tac /tmp/tmpfile > "$HISTFILE"
rm /tmp/tmpfile
  • histappend 옵션은 버퍼 히스토리를 히스토리 파일의 끝에 추가합니다 ($ HISTFILE)
  • ignoreboth 및 erasedups는 중복 항목이 $ HISTFILE에 저장되지 않도록합니다.
  • prompt 명령은 히스토리 캐시를 업데이트합니다
    • history -n 마지막 캐리지 리턴 이후 다른 터미널에서 발생했을 수있는 $ HISTFILE에서 모든 행을 읽습니다.
    • history -w 업데이트 된 버퍼를 $ HISTFILE에 씁니다.
    • history -c 중복이 발생하지 않도록 버퍼를 지 웁니다.
    • history -r 이제 빈 버퍼에 추가하여 $ HISTFILE을 다시 읽습니다.
  • awk 스크립트는 처음 발견 된 각 행을 저장합니다. tac역사상 가장 최근의 명령으로 저장할 수 있도록 역순으로 되 돌린 후 역순으로
  • rm / tmp 파일

새 쉘을 열 때마다 내역이 모두 지워지고 Enter다른 쉘 / 터미널 창에서 키를 누를 때마다 파일에서이 내역이 업데이트됩니다.



"무시 및 소거로 인해 듀피가 저장되지 않는 경우"파일에서 듀피를 제거하기 위해 "awk"명령을 수행해야하는 이유는 무엇입니까? "무시 및 소거"는 연속 된 듀피 가 저장되는 것을 막기 때문 입니까? pedantic해서 죄송합니다. 이해하려고 노력하고 있습니다.
— Jonathan Hartley

1
erasedups는 연속 복제 만 지 웁니다. 그리고 awk 명령이 erasedupes 명령을 복제하여 불필요한 것으로 만듭니다.
— smilingfrog

고마워요, 무슨 일이 일어나고 있는지 분명해집니다.
— Jonathan Hartley

0

모든 새로운 명령을 확실하게 기록하는 것은 까다 롭습니다. 먼저 다음을 추가 ~/.profile하거나 유사하게 해야합니다 .

HISTCONTROL=erasedups
PROMPT_COMMAND='history -w'

그런 다음에 추가해야합니다 ~/.bash_logout.

history -a
history -w

로그 아웃 할 때 전체 기록 파일을 다시 작성하기 전에 기록되지 않은 기록을 기록 파일에 추가해야하는 이유를 이해할 수 있습니까? '추가'없이 전체 파일을 쓸 수는 없습니까?
— Jonathan Hartley
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.