.hgignore
오늘 Cygwin bash 쉘에서 파일 을 신속하게 편집하려고 시도했지만 실수 한 줄을 추가했습니다. 이것이 최선의 방법인지 확실하지 않지만 head -1 .hgignore
문제를 일으키는 줄을 제거하는 데 빨리 생각했습니다 (이전에 파일에 한 줄만있었습니다). 물론 실행될 때 첫 번째 줄을 유일한 출력으로 제공합니다.
그러나 출력을 리디렉션하고을 사용하여 파일을 다시 쓰려고 할 head -1 .hgignore > .hgignore
때 파일이 비어있었습니다. 왜 이런 일이 발생합니까? 대신을 추가하려고하면 head -1 .hgignore >> .hgignore
올바르게 추가되지만 원하는 결과는 아닙니다. 이 경우 잘림 리디렉션이 작동하지 않는 이유는 무엇입니까?
답변
쉘이 다음과 같은 명령 행을 받으면 : command > file.out
쉘 자체가라는 파일을 열고 (아마도 작성합니다) file.out
. 쉘은 파일 디스크립터 0을 파일 파일 디스크립터로 설정합니다. 이것이 I / O 리디렉션의 작동 방식입니다. 모든 프로세스는 파일 디스크립터 0, 1 및 2에 대해 알고 있습니다.
이것에 대한 어려운 부분은 여는 방법file.out
입니다. 대부분의 경우 file.out
오프셋 0 (즉, 잘림)으로 쓰기 위해 열려고합니다. 이것이 쉘이 수행 한 작업입니다. .hgignore를 자르고, 쓰기 위해 열었고, 파일 기술자를 0으로 dup 한 다음 exec’ed했습니다 head
. 즉각적인 파일 클로버 링.
bash 셸에서는 set noclobber
이 동작을 변경합니다.
답변
Bruce 는 쉘 파이프 라인 으로 여기서 무슨 일이 일어나고 있는지 대답 합니다 .
내가 가장 좋아하는 작은 유틸리티 중 하나는 moreutils 의 sponge
명령입니다 . 대상 출력 파일을 열고 데이터를 쓰기 전에 사용 가능한 모든 입력을 “잠글”하여이 문제를 정확하게 해결합니다. 예상대로 정확하게 파이프 라인을 작성할 수 있습니다.
$ head -1 .hgignore | sponge .hgignore
가난한 사람의 해결책은 출력을 임시 파일로 파이프하는 것입니다. 그런 다음 pipline이 완료된 후 (예를 들어 다음 명령 실행) 임시 파일을 원래 파일 위치로 다시 이동하는 것입니다.
$ head -1 .hgingore > .hgignore.tmp
$ mv .hgignore{.tmp,}
답변
에
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
커서 위치를 stdin으로 이동시키는 사실을 사용하고 있습니다. 하지만 head
일반적으로 성능을 향상시키기 위해 큰 덩어리로 입력을 읽을 것, POSIX는 그것을 (수) 필요 seek
그것을 넘어 들어갔 더라면 바로 첫 번째 줄 이후에 백업 할 수 있습니다. 그러나 모든 구현이 그렇지는 않습니다.
또는 read
이 경우 대신 쉘 명령을 사용할 수 있습니다 .
{ read -r dummy; perl -e 'truncate STDIN, tell STDIN'; } <> file
답변
진짜 남자의 해결책은
ed .hgignore
$d
wq
또는 하나의 라이너
printf '%s\n' '$d' 'wq' | ed .hgignore
또는 GNU sed와 함께 :
sed -i '$d' .hgignore
(아니요, 농담입니다. 대화 형 편집기를 사용하겠습니다. vi .hgignore
GddZZ
)
답변
Ex 모드에서 Vim을 사용할 수 있습니다 :
ex -sc '2,d|x' .hgignore
-
2,
끝까지 라인 2를 선택 -
d
지우다 -
x
저장하고 닫습니다
답변
전체 파일 편집을 위해 Jürgen Hötzel이 sed ‘s / c / d /’myFile에서 myFile으로 경로 재 지정 출력 에 표시된대로 열린 파일 핸들 트릭을 사용할 수도 있습니다 .
exec 3<.hgignore
rm .hgignore # prevent open file from being truncated
head -1 <&3 > .hgignore
ls -l .hgignore # note that permissions may have changed