누군가는 생각할지도 모른다
echo foo >a
cat a | rev >a
a
포함된 채로 남아 있지만 oof
비어 있습니다.
- 왜?
- 또 어떻게
rev
적용 되나요a
?
답변1
이를 위한 앱이 있습니다! sponge
from 명령은 moreutils
바로 이것을 위해 설계되었습니다. Linux를 실행 중이라면 이미 설치되어 있을 것입니다. 그렇지 않은 경우 운영 체제 저장소에서 sponge
또는 를 검색하세요 moreutils
. 그런 다음 다음을 수행할 수 있습니다.
echo foo >a
cat a | rev | sponge a
아니면 피하세요우루크:
rev a | sponge a
이 동작의 이유는 명령이 실행되는 순서에 따라 다릅니다. 실제로 > a
가장 먼저 실행되고 > file
파일을 지웁니다. 예를 들어:
$ echo "foo" > file
$ cat file
foo
$ > file
$ cat file
$
따라서 실행할 때 cat a | rev >a
실제로 일어나는 일은 > a
먼저 실행되어 파일을 비우므로 cat a
실행될 때 파일이 이미 비어 있는 것입니다. 이것이 바로 sponge
다음과 같이 작성된 이유입니다( man sponge
, 강조 내 항목).
Sponge는 표준 입력을 읽고 이를 지정된 파일에 씁니다. 쉘 리디렉션과 달리 스폰지는 출력 파일에 쓰기 전에 모든 입력을 흡수합니다. 이를 통해 동일한 파일을 읽고 쓰는 파이프라인을 구축할 수 있습니다.
답변2
- 출력 잘림이 일찍 수행되므로 cat은 빈 파일을 봅니다.
- 첫 번째 파일을 임시 파일로 구성하거나 나중에 이름을 바꿀 임시 파일로 rev의 출력을 지정합니다.
답변3
이 문제를 해결하는 또 다른 방법은 잘림 없이 쓰기 메소드를 사용하는 것입니다.
rev a | dd conv=notrunc of=a
이는 다음과 같은 이유로만 작동합니다.
rev는 출력을 생성하기 전에 내용을 읽으며 출력은 읽은 양보다 길지 않습니다.
새 파일 내용은 원본 파일 내용과 동일하거나 더 큽니다(이 경우 크기는 동일함).
- dd는 파일을 자르지 않고 쓰기 위해 파일을 엽니다.
이 방법은 너무 커서 임시 복사본을 보관할 수 없는 파일을 내부 수정하는 데 유용할 수 있습니다.
답변4
>file
새로운 빈 파일을 생성하거나 기존 파일을 자릅니다. 따라서 파일에 읽을 내용이 없습니다 rev
.
sponge
다른 답변에서 언급했듯이 이 목적 으로 사용할 수 있습니다 . 그러나 sponge
모든 사람이 사용할 수 있는 것은 아닙니다.
쉘과 관련된 일반적인 솔루션은 다음과 같습니다.
exec 3<file; rm file; rev <&3 >file; exec 3<&-
그러면 파일(예: fd 3)이 열리고 삭제됩니다. 보다 정확하게는 파일 자체가 아닌 파일의 디렉토리 항목만 삭제합니다. 파일에 대한 모든 하드 링크가 제거되고 파일에 대한 모든 핸들이 닫힐 때까지 파일은 삭제되지 않습니다.
다음으로 rev
"삭제된 파일"에서 읽기를 실행합니다. 출력은 새 파일로 전송됩니다. 이 새 파일은 원본 파일과 이름이 동일하지만 다른 파일입니다. 그러므로 갈등이 없습니다.
마지막으로 원본 파일의 설명자를 닫아 해제합니다.
위 접근 방식의 문제점은 문제가 발생하면 데이터가 손실된다는 것입니다. 그렇기 때문에 다음을 선호할 수 있습니다(위보다 더 많은 디스크 공간을 사용하지 않음).
( rev file >file.new && mv file.new file ) || rm file.new