Linux : 파일을 동시에 입력 및 출력으로 사용하는 방법은 무엇입니까?


55

방금 bash에서 다음을 실행했습니다.

uniq .bash_history > .bash_history

내 역사 파일이 완전히 비워졌습니다.

쓰기 전에 전체 파일을 읽는 방법이 필요하다고 생각합니다. 어떻게됩니까?

추신 : 분명히 임시 파일을 사용하려고 생각했지만 더 우아한 해결책을 찾고 있습니다.


파일이 오른쪽에서 왼쪽으로 열리기 때문입니다. 또한 참조 stackoverflow.com/questions/146435/...
WheresAlice

동일한 디렉토리의 새 파일에 출력을 작성하고 이전 파일의 이름을 바꿔야합니다. 다른 접근 방식은 데이터가 중간에 중단되면 데이터가 손실 될 수 있습니다. 일부 도구는이 단계를 숨길 수 있습니다.
kasperd

또는 bashHISTCONTROL을 무시하도록 설정 한 경우 연속 기록을 기록에 포함시키지 않습니다. 맨 페이지를 참조하십시오.
dave_thompson_085

답변:


49

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

6
그것은 고양이처럼,하지만 기능을 빠는와 함께입니다 : D
MilliaLover

77

나는 단지 간단하고 스폰지를 사용하지 않는 또 다른 답변을 제공하고 싶었습니다 (가벼운 환경에 종종 포함되지 않기 때문에).

echo "$(uniq .bash_history)" > .bash_history

원하는 결과가 있어야합니다. 서브 쉘은 쓰기 위해 .bash_history를 열기 전에 실행됩니다. Phil P의 답변에서 설명했듯이 원래 명령에서 .bash_history를 읽을 때까지 이미 '>'연산자로 잘 렸습니다.


15
나는 일반적으로 이미 유효하고 받아 들여지는 답을 가지고있는 고대의 질문을 준 답안의 팬이 아니다. 그러나 이것은 우아하고 잘 작성되어 있으며, 그 필요성 (가벼운 환경)에 대한 강력한 논증을한다. 나를 위해, 그것은 실제로 기존 답변 세트에 무언가를 추가합니다. SF, Hart에 오신 것을 환영합니다. 나는 이것처럼 당신으로부터 더 많은 답변을 읽을 수 있기를 바랍니다!
MadHatter

4
이것이 가장 좋은 해결책입니다. $()이스케이프 문제로 인해 백틱 대신 서브 셸을 사용해야했습니다 .
CMCDragonkai

3
이 솔루션이 20 또는 50GB와 같은 큰 파일로 확장되는지 궁금합니다.
Amit Naidu

1
이것은 실제로 수락 답변이어야합니다.
maxywb

1
나는 echo "$(fmt -p '# ' -w 50 readme.txt)" > readme.txt오늘 이 대답을 사용했습니다 . 우아한 솔루션을 찾기 위해 오랫동안 주위를 찾고있었습니다. 많은 감사합니다, @Hart Simha!
shredalert

12

문제는 명령을 실행하기 전에 쉘이 명령 파이프 라인을 설정하고 있다는 것입니다. 그것은 "입력 및 출력"의 문제가 아니며, 파일의 내용이 이미 uniq가 실행되기 전에 이미 사라졌기 때문입니다. 그것은 다음과 같습니다 :

  1. 쉘은 >출력을 위해 출력 파일을 열어서 잘 립니다.
  2. 쉘은 그 출력에 파일 디스크립터 1 (stdout)이 사용되도록 설정합니다.
  3. 쉘은 아마도 execlp ( "uniq", "uniq", ".bash_history", NULL)와 같은 uniq을 실행합니다.
  4. uniq가 실행되고 .bash_history가 열리고 아무것도 발견되지 않습니다.

내부 편집 및 다른 사람들이 언급 한 임시 파일 사용을 포함하여 다양한 솔루션이 있지만 문제의 핵심은 실제로 문제가 발생하는 이유와 이유를 이해하는 것입니다.


9

을 사용하지 않고 이것을 수행하는 또 다른 트릭 sponge은 다음 명령입니다.

{ rm .bash_history && uniq > .bash_history; } < .bash_history

이것은 backreference.org 에서 파일의 "In-place"편집 에 관한 훌륭한 기사에서 설명한 속임수 중 하나입니다 .

기본적으로 읽을 파일을 연 다음 "제거"합니다. 그러나 실제로 제거되지는 않습니다. 파일을 가리키는 열린 파일 설명자가 있으며 열려있는 한 파일은 여전히 ​​존재합니다. 그런 다음 이름이 같은 새 파일을 작성하고 고유 한 행을 작성합니다.

이 솔루션의 단점 : uniq어떤 이유로 든 실패하면 기록이 사라집니다.



3

sed스크립트는 인접한 중복을 제거합니다. 이 -i옵션을 사용하면 수정이 제자리에서 수행됩니다. sed info파일 에서 온 것입니다 .

sed -i 'h;:b;$b;N;/^\(.*\)\n\1$/ {g;bb};$b;P;D' .bash_history

sed는 여전히 임시 파일을 사용하고, 설명이 포함 된 답변을 추가 strace했습니다 (실제로 중요하지 않음) :-)
Kyle Brandt

3
@Kyle : 맞습니다. 그러나 "눈에 보이지 않습니다." 개인적으로, 같은 것이 이후는 명시 적으로 임시 파일을 사용하는 것이 process input > tmp && mv tmp input훨씬 간단하고 사용하는 것보다 더 읽을 수 sed있을지 모르겠어요 (임시 파일을 방지하기 위해 단순히 속임수를하고 실패 할 경우 내 원본을 덮어 쓰지 않습니다 sed -i정상적으로 실패 - 나는 것 그래도 생각합니다). 게다가,이 sed스크립트 보다 더 복잡한 작업 없이는 수행 할 수없는 파일로 출력 방법으로 할 수있는 일이 많이 있습니다. 나는 당신이이 모든 것을 알고 있다는 것을 알고 있지만, 일부 구경꾼에게는 도움이 될 수 있습니다.
Dennis Williamson

3

흥미로운 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 파일을 덮어 씁니다.



0

문제의 명령이 제자리에서 편집을 지원하지 않는 한 임시 파일은 거의 파일입니다 ( uniq일부 sed작업은 수행 하지 않습니다 ( sed -i)).


0

Ex 모드에서 Vim을 사용할 수 있습니다 :

ex -sc '%!uniq' -cx .bash_history
  1. % 모든 줄을 선택하십시오

  2. ! 명령을 실행

  3. x 저장하고 닫습니다


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.