오늘 저는 Cygwin bash 쉘에서 파일을 빠르게 편집하려고 하다가 .hgignore
잘못된 줄을 추가했습니다. 이것이 최선의 접근 방식인지는 확실하지 않지만 head -1 .hgignore
문제가 있는 줄을 삭제하는 방법을 빠르게 생각했습니다(이전에는 파일에 한 줄만 있었습니다). 물론, 실행되면 첫 번째 줄이 유일한 출력으로 제공됩니다.
그러나 출력을 리디렉션하고 rewrite file 을 사용하려고 하면 head -1 .hgignore > .hgignore
파일이 비어 있습니다. 왜 이런 일이 발생합니까? 부착하려고 하면 head -1 .hgignore >> .hgignore
올바르게 부착되지만 분명히 원하는 결과는 아닙니다. 이 경우 잘린 리디렉션이 작동하지 않는 이유는 무엇입니까?
답변1
내 생각엔 브루스가 대답할 것 같아여기서 무슨 일이 일어나고 있나요?하우징 배관 포함.
내가 가장 좋아하는 작은 유틸리티 중 하나 sponge
는더 많은 유틸리티. 대상 출력 파일을 열고 데이터를 쓰기 전에 사용 가능한 모든 입력을 "싱크"하여 이 문제를 해결합니다. 이를 통해 의도한 대로 정확하게 파이프라인을 작성할 수 있습니다.
$ head -1 .hgignore | sponge .hgignore
가난한 사람의 해결책은 출력을 임시 파일로 파이프한 다음 파이프가 완료된 후(예: 실행하는 다음 명령) 임시 파일을 원래 파일 위치로 다시 이동하는 것입니다.
$ head -1 .hgingore > .hgignore.tmp
$ mv .hgignore{.tmp,}
답변2
쉘이 다음과 같은 명령줄을 받으면: command > file.out
쉘 자체는 이라는 파일을 엽니다(그리고 생성할 수도 있습니다) file.out
. 쉘은 파일 설명자 0을 열려서 얻은 파일 설명자로 설정합니다. 이것이 I/O 리디렉션이 작동하는 방식입니다. 각 프로세스는 파일 설명자 0, 1, 2에 대해 알고 있습니다.
가장 어려운 부분은어떻게열려 있는 file.out
. 대부분의 경우 file.out
쓰기 위해 오프셋 0(즉, 잘라내기)에서 열기를 원하며 이것이 쉘이 수행하는 작업입니다. .hgignore를 자르고 쓰기 위해 열고 파일 설명자를 0으로 복사한 다음 exec를 실행합니다 head
. 즉각적인 파일 손상.
Bash 쉘에서는 set noclobber
다음을 수행하여 이 동작을 변경할 수 있습니다.
답변3
존재하다
head -n 1 file > file
file
head
시작하기 전에 잘렸지만 작성하는 경우:
head -n 1 file 1<> file
file
읽기-쓰기 모드에서는 열리지 않습니다 . 그러나 head
쓰기가 완료되면 파일이 잘리지 않으므로 위 줄은 작동하지 않습니다( head
첫 번째 줄 자체만 다시 작성되고 다른 줄은 변경되지 않은 채 유지됩니다).
그러나 head
반환 후 fd
아직 열려 있는 동안 다른 실행을 호출할 수 있습니다 truncate
.
예를 들어:
{ head -n 1 file; perl -e 'truncate STDOUT, tell STDOUT'; } 1<> file
여기서 중요한 점은 truncate
위 내용이 head
파일의 첫 번째 줄 이후 fd 1로만 커서를 이동한다는 것입니다. 우리에게 필요하지 않은 첫 번째 줄을 다시 작성하지만, 거기에는 아무런 해가 없습니다.
POSIX 헤더를 사용하면 첫 번째 줄을 다시 작성하지 않고도 실제로 벗어날 수 있습니다.
{ head -n 1 > /dev/null
perl -e 'truncate STDIN, tell STDIN'
} <> file
head
여기서는 표준 입력에서 커서 위치를 이동한다는 사실을 사용합니다. 일반적 으로 head
입력을 청크로 읽으면 성능이 향상되지만 POSIX에서는 가능하면 seek
첫 번째 줄을 초과하자마자 반환해야 합니다. 그러나 모든 구현이 이 작업을 수행하는 것은 아닙니다.
read
또는 이 경우 셸의 명령을 사용할 수 있습니다.
{ read -r dummy; perl -e 'truncate STDIN, tell STDIN'; } <> file
답변4
Ex 모드에서 Vim을 사용할 수 있습니다:
ex -sc '2,d|x' .hgignore
2,
2행을 끝까지 선택하세요.d
삭제x
저장하고 닫습니다