방금 bash에서 다음을 실행했습니다.
uniq .bash_history > .bash_history
내 역사 파일이 완전히 비워졌습니다.
쓰기 전에 전체 파일을 읽는 방법이 필요하다고 생각합니다. 어떻게됩니까?
추신 : 분명히 임시 파일을 사용하려고 생각했지만 더 우아한 해결책을 찾고 있습니다.
bash
HISTCONTROL을 무시하도록 설정 한 경우 연속 기록을 기록에 포함시키지 않습니다. 맨 페이지를 참조하십시오.
방금 bash에서 다음을 실행했습니다.
uniq .bash_history > .bash_history
내 역사 파일이 완전히 비워졌습니다.
쓰기 전에 전체 파일을 읽는 방법이 필요하다고 생각합니다. 어떻게됩니까?
추신 : 분명히 임시 파일을 사용하려고 생각했지만 더 우아한 해결책을 찾고 있습니다.
bash
HISTCONTROL을 무시하도록 설정 한 경우 연속 기록을 기록에 포함시키지 않습니다. 맨 페이지를 참조하십시오.
답변:
moreutilssponge
에서 사용 하는 것이 좋습니다 . 맨 페이지에서 :
DESCRIPTION
sponge reads standard input and writes it out to the specified file. Unlike
a shell redirect, sponge soaks up all its input before opening the output file.
This allows for constructing pipelines that read from and write to the same
file.
이것을 문제에 적용하려면 다음을 시도하십시오.
uniq .bash_history | sponge .bash_history
나는 단지 간단하고 스폰지를 사용하지 않는 또 다른 답변을 제공하고 싶었습니다 (가벼운 환경에 종종 포함되지 않기 때문에).
echo "$(uniq .bash_history)" > .bash_history
원하는 결과가 있어야합니다. 서브 쉘은 쓰기 위해 .bash_history를 열기 전에 실행됩니다. Phil P의 답변에서 설명했듯이 원래 명령에서 .bash_history를 읽을 때까지 이미 '>'연산자로 잘 렸습니다.
$()
이스케이프 문제로 인해 백틱 대신 서브 셸을 사용해야했습니다 .
echo "$(fmt -p '# ' -w 50 readme.txt)" > readme.txt
오늘 이 대답을 사용했습니다 . 우아한 솔루션을 찾기 위해 오랫동안 주위를 찾고있었습니다. 많은 감사합니다, @Hart Simha!
문제는 명령을 실행하기 전에 쉘이 명령 파이프 라인을 설정하고 있다는 것입니다. 그것은 "입력 및 출력"의 문제가 아니며, 파일의 내용이 이미 uniq가 실행되기 전에 이미 사라졌기 때문입니다. 그것은 다음과 같습니다 :
>
출력을 위해 출력 파일을 열어서 잘 립니다.내부 편집 및 다른 사람들이 언급 한 임시 파일 사용을 포함하여 다양한 솔루션이 있지만 문제의 핵심은 실제로 문제가 발생하는 이유와 이유를 이해하는 것입니다.
을 사용하지 않고 이것을 수행하는 또 다른 트릭 sponge
은 다음 명령입니다.
{ rm .bash_history && uniq > .bash_history; } < .bash_history
이것은 backreference.org 에서 파일의 "In-place"편집 에 관한 훌륭한 기사에서 설명한 속임수 중 하나입니다 .
기본적으로 읽을 파일을 연 다음 "제거"합니다. 그러나 실제로 제거되지는 않습니다. 파일을 가리키는 열린 파일 설명자가 있으며 열려있는 한 파일은 여전히 존재합니다. 그런 다음 이름이 같은 새 파일을 작성하고 고유 한 행을 작성합니다.
이 솔루션의 단점 : uniq
어떤 이유로 든 실패하면 기록이 사라집니다.
moreutils의 스폰지 사용
uniq .bash_history | sponge .bash_history
이 sed
스크립트는 인접한 중복을 제거합니다. 이 -i
옵션을 사용하면 수정이 제자리에서 수행됩니다. sed
info
파일 에서 온 것입니다 .
sed -i 'h;:b;$b;N;/^\(.*\)\n\1$/ {g;bb};$b;P;D' .bash_history
strace
했습니다 (실제로 중요하지 않음) :-)
process input > tmp && mv tmp input
훨씬 간단하고 사용하는 것보다 더 읽을 수 sed
있을지 모르겠어요 (임시 파일을 방지하기 위해 단순히 속임수를하고 실패 할 경우 내 원본을 덮어 쓰지 않습니다 sed -i
정상적으로 실패 - 나는 것 그래도 생각합니다). 게다가,이 sed
스크립트 보다 더 복잡한 작업 없이는 수행 할 수없는 파일로 출력 방법으로 할 수있는 일이 많이 있습니다. 나는 당신이이 모든 것을 알고 있다는 것을 알고 있지만, 일부 구경꾼에게는 도움이 될 수 있습니다.
흥미로운 tidbit로서, sed는 임시 파일도 사용합니다 (이것은 당신을 대신합니다).
$ strace sed -i 's/foo/bar/g' foo
open("foo", O_RDONLY|O_LARGEFILE) = 3
...
open("./sedPmPv9z", O_RDWR|O_CREAT|O_EXCL|O_LARGEFILE, 0600) = 4
...
read(3, "foo\n"..., 4096) = 4
write(4, "bar\n"..., 4) = 4
read(3, ""..., 4096) = 0
close(3) = 0
close(4) = 0
rename("./sedPmPv9z", "foo") = 0
close(1) = 0
close(2) = 0
설명 :
임시 파일 ./sedPmPv9z
은 fd 4가되고 foo
파일은 fd 3이됩니다. 읽기 작업은 fd 3에 있고 fd 4 (임시 파일)에 기록됩니다. 그런 다음 이름 바꾸기 호출에서 임시 파일로 foo 파일을 덮어 씁니다.
uniq 출력을 입력으로 사용하여 티도 사용할 수 있습니다.
uniq .bash_history | tee .bash_history