.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 -ahistory -w각각.


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

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