:>filename.txt
예를 들어:
root@box$ dd if=/dev/zero of=file.txt count=1024 bs=1024
1024+0 records in
1024+0 records out
1048576 bytes (1.0 MB, 1.0 MiB) copied, 0.00536175 s, 196 MB/s
root@box$ ll
total 1024
-rw-r--r-- 1 root root 1048576 Nov 15 14:40 file.txt
root@box$ :>file.txt
root@box$ ll
total 0
-rw-r--r-- 1 root root 0 Nov 15 14:40 file.txt
이것은 다른가요 rm
? 파일을 비우거나 삭제하는 다른 유사한 방법보다 더 빠르게 실행됩니까, 아니면 느리게 실행됩니까?
답변1
rm
아시다시피 이는 단순히 파일 내용을 비우는 것입니다(파일을 자릅니다). 이는 실제로 rm
파일을 완전히 삭제하는 것과는 다릅니다 . 게다가 :>file.txt
실제로는만들다아직 존재하지 않는 경우 이 파일입니다.
:
성공적으로 종료되고 출력이 생성되지 않는 "아무 것도 하지 않는 명령"이므로 파일을 비우는 간단한 방법일 뿐입니다. 대부분의 쉘에서는 >file.txt
간단히 이렇게 하면 동일한 결과를 얻을 수 있습니다. 또한 외부 명령과 같은 다른 방법보다 약간 더 빠를 수도 echo >file.txt
있습니다 echo
.
echo >file.txt
또한 내부에 빈 줄이 배치되어 파일에 내용이 없습니다.file.txt
:>file.txt
답변2
네, 다릅니다 rm
.
rm
파일이 삭제됩니다.
:>filename.txt
파일이 여전히 존재하지만 크기가 0바이트가 되도록 파일을 비웁니다.
답변3
쉘 호출은 >filename.txt
일부 출력을 "filename.txt" 파일로 리디렉션하여 완전히 대체합니다. 따라서 쉘은 지정된 파일에 출력을 쓰기 전에 지정된 파일의 모든 내용을 지워야 합니다.
리디렉션되는 출력은 실행된 명령의 출력입니다. 좋다:
$ echo Hello >filename.txt
filename.txt라는 파일에 문자열만 정확하게 포함됩니다 Hello
.
구현하다:
$ echo "New Value" >filename.txt
$ cat filename.txt
New Value
파일 내의 모든 내용이 지워진 다음 New Value
파일에 기록됩니다.
명령에 출력이 없으면(명령에서와 같이) true
파일은 비어 있는(잘린 상태) 상태로 유지됩니다.
$ true >filename.txt
$ cat filename.txt
쉘 내장 명령이기도 한 명령은 :
(단지 이중 점(콜론))이며 출력이 없습니다. 내장 명령이므로 true
출력이 없는 외부 명령보다 빠릅니다. 따라서 다음 중 하나를 수행하세요.
$ : > filename.txt
$ : >filename.txt
$ :>filename.txt
지정된 파일에서 모든 내용이 삭제되며 filename.txt
, 존재하지 않는 경우 빈 파일로 생성됩니다.
rm이랑 다른건가요?
이는 rm과 다릅니다. rm은 ls
파일에 0바이트를 포함시키는 대신 파일을 사라지게 만들기 때문입니다.
파일을 비우거나 삭제하는 다른 유사한 방법보다 더 빠르게 실행됩니까, 아니면 느리게 실행됩니까?
다시 말하지만, 파일은 삭제되지 않고(주어진 목록에서 사라짐 ls
) 빈 파일(0바이트 포함)로 변환됩니다.
파일을 비우기 위해 외부 명령을 호출하는 것보다 빠릅니다. 실행 파일과 명령을 로드하려면 하위 쉘을 생성해야 하므로 exec
외부 명령이 내장 명령보다 느려집니다 :
.
유사한 솔루션은 다음과 같습니다(일부는 $?
1로 설정됨).
[ ] > filename.txt
builtin > filename.txt
command > filename.txt
printf '' > filename.txt
답변4
답: 성능: 이는 쉘에서 가능한 한 효율적입니다. 단순히 커널에 기존 파일을 자르도록 요청하는 것이 파일 링크를 해제하고 동일한 이름으로 새 inode를 다시 생성하는 것보다 더 효율적입니다. 너가 아니라면생각하다파일이 삭제되었습니다. 이 경우에는 rm
여전히 unlink
남아 있습니다.
:
내장 쉘이므로 포크/실행이 필요하지 않습니다. true
일반적인 현대 껍질의 경우에도 마찬가지입니다.
>foo
또는 시스템 호출을 통해 true > foo
쉘이 파일을 자르도록 합니다 .
open(path, O_WRONLY|O_TRUNC|O_CREAT, 0666)
strace sh
또는 출력 을 판단하여 Linux에서 DASH를 사용하여 연습해 보십시오 .
openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
이는 동일합니다.
그럼 다시 그 FD로 가야 해요 close()
. 실제로 DASH를 사용할 때는 특별한 경우가 없으며 :>
다음 단계를 건너뜁니다.
openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
fcntl(1, F_GETFD) = 0
fcntl(1, F_DUPFD, 10) = 10 # save original stdout
fcntl(1, F_GETFD) = 0
fcntl(10, F_SETFD, FD_CLOEXEC) = 0
dup2(3, 1) = 1 # redirect stdout to foo
close(3) = 0 # then close 3
dup2(10, 1) = 1 # then restore original stdout
fcntl(10, F_GETFD) = 0x1 (flags FD_CLOEXEC)
close(10) = 0
DASH에서 사용하면 > foo
동일한 시스템 호출 시퀀스가 발생하여 실제로 fd1을 리디렉션한 다음 복원합니다. 나는 수표 bash
나 다른 껍질이 없습니다 .
그러나 실행할 새 프로세스를 생성하고 truncate -s 0 foo
(희망적으로) 단일 프로세스를 만드는 것보다 여전히 훨씬 저렴합니다.truncate("foo", 0)
시스템 호출open
이는 + 보다 더 효율적일 수 있습니다 close
.
C(또는 시스템 호출 바인딩이 있는 모든 언어)에서는 열고 싶지 않은 파일은 직접 시스템 호출을 통해 가장 효율적으로 잘립니다 truncate
.
Dash에서는 3>foo
다음과 같은 시스템 호출 순서가 발생합니다.
openat(AT_FDCWD, "foo", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
close(3) = 0
새 fd를 열면 이미 fd 3이 되어 중복이 방지됩니다. 이는 대시에서 가장 효율적인 방법으로, 아마도 >foo
. 이것이 중요하다면 쉘 스크립팅 언어는 귀하의 작업에 적합하지 않습니다! 하지만 당신은 물었습니다.
Spectre+Meltdown 완화를 활성화하면 -ENOSYS
최신 Intel x86-64에서 잘못된 시스템 호출에도 최소 수천 클럭 사이클(예: 마이크로초)이 소요됩니다. 단 하나의 명령으로 syscall
수백 번의 사용자->커널->사용자 왕복을 달성할 수 있습니다 . 물론 경로 조회 등은 파일 시스템 코드와 마찬가지로 많은 시간이 걸립니다. 커널 모드로 들어갔다가 돌아오면 일반적으로 일부 캐시가 제거되어 반환 시 사용자 공간 실행 속도가 느려집니다.
메타데이터를 디스크에 다시 기록한 후의 실제 I/O 비용은 파일 시스템에 따라 다릅니다. XFS 또는 최신 ext4와 같은 FS는 전체 파일에서 1개 또는 몇 개의 큰 범위만 사용하여 O(1) 시간에 많은 공간을 쉽게 확보할 수 있습니다. 또는 O(n), 여기서 는 n
바이트 크기가 아닌 범위(조각) 수입니다.
FS에 따르면, 익스텐트 정보가 간접 블록이 아닌 아이노드에 직접 저장된다면, 여유 목록에 추가할 것이 하나 줄어든다.
I/O 비용은 파일 링크 해제와 비슷하지만 inode를 해제하거나 디렉터리 항목을 수정할 필요는 없습니다. 잘라낼 때 inode에서 mtime과 ctime을 업데이트해야 하지만 크기가 변경되면 어쨌든 이에 작성해야 합니다.