sed 또는 tail 파일에서 첫 번째 줄을 삭제하는 것이 더 빠릅니까?


14

이 답변 ( sed로 파일의 첫 번째 줄을 어떻게 제거 할 수 있습니까? )에는 파일의 첫 번째 레코드를 삭제하는 두 가지 방법이 있습니다.

sed '1d' $file >> headerless.txt

** ---------------- 또는 ---------------- **

tail -n +2 $file >> headerless.txt

개인적으로 나는 tail옵션이 외관상 더 즐겁고 읽기 쉽다고 생각 하지만 아마도 sed에 도전했기 때문일 것입니다.

어떤 방법이 가장 빠릅니까?


5
대답은 아니지만 가능한 고려 사항은 sed이식성이 뛰어나다 는 것 입니다. "+2" tail는 GNU를 사용하는 우분투에서는 tail잘 작동하지만 BSD에서는 작동하지 않습니다 tail.
John N

@JohnN tail은 크로스 플랫폼 호환성 부족 을 공유해 주셔서 감사합니다 .
WinEunuuchs2Unix

3
@ 존 N "2"는 꼬리의 BSD 꼬리 명령을 사용할 주장 시에라을 실행하는 5 월 Mac에서 잘 작동합니다
닉 Sillito

어이, 당신 말이 맞아요-방금 다시 실행했는데 이번에는 입력을 확인했습니다. 내가 처음으로해야했던 것. POSIX이기도합니다. 부끄러워 / slinks.
John N

2
@JohnN 당신은 완전히 잘못되지 않았습니다. 과거에는 UNIX가 -n옵션을 제공하지 않았 으며 구문을 사용했습니다 tail +2 $file. freebsd.org/cgi/…를 참조하십시오 . 현대 BSD 중 하나가 아니라 생각할 수도 있습니다.
hvd

답변:


28

파일의 첫 번째 줄을 제거하는 것과 sed비교 한 성능tail

TL; DR

  • sed 매우 강력하고 다재다능하지만 특히 줄이 많은 대용량 파일의 경우 속도가 느려집니다.

  • tail 하나의 간단한 일을하지만 많은 줄을 가진 더 큰 파일의 경우에도 잘하고 빠릅니다.

중소 파일의 경우, sed그리고 tail(여러분의 기대에 따라, 또는 천천히) 빠른 유사하게 수행된다. 그러나 더 큰 입력 파일 (여러 MB)의 경우 성능 차이가 눈에 띄게 커지고 (수백 MB 범위의 파일의 경우 수십 배) tail분명히 성능이 뛰어납니다 sed.

실험

일반적인 준비 사항 :

분석 명령은 다음과 같습니다.

sed '1d' testfile > /dev/null
tail -n +2 testfile > /dev/null

/dev/null터미널 출력 또는 파일 쓰기를 성능 병목 현상으로 제거 하기 위해 매번 출력을 파이핑하고 있습니다.

잠재적 인 병목 현상으로 디스크 I / O를 제거하기 위해 RAM 디스크를 설정합시다. 나는 개인적으로 tmpfs탑재되어 있으므로이 실험을 위해 /tmp단순히 testfile거기에 배치 했습니다.

그런 다음 $numoflines이 명령을 사용하여 임의의 줄 길이와 임의의 데이터 가있는 지정된 양의 줄 을 포함하는 임의의 테스트 파일을 한 번 만듭니다 (확실히 최적은 아니며 약 2M 줄 이상에서는 실제로 느려집니다. 그러나 누가 신경 쓰지 않습니까? 우리가 분석하는 것) :

cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n "$numoflines" > testfile

아, btw. 내 테스트 랩톱은 Intel i5-6200U CPU에서 Ubuntu 16.04, 64 비트를 실행 중입니다. 비교를 위해.

큰 파일 타이밍 :

거대한 설정 testfile:

numoflines=10000000600MB가 넘는 비트를 차지하는 10M 라인을 포함하는 임의의 파일 을 생성하여 위의 명령을 실행하면 상당히 크지 만 시작할 수 있습니다.

$ wc -l testfile 
10000000 testfile

$ du -h testfile 
611M    testfile

$ head -n 3 testfile 
qOWrzWppWJxx0e59o2uuvkrfjQbzos8Z0RWcCQPMGFPueRKqoy1mpgjHcSgtsRXLrZ8S4CU8w6O6pxkKa3JbJD7QNyiHb4o95TSKkdTBYs8uUOCRKPu6BbvG
NklpTCRzUgZK
O/lcQwmJXl1CGr5vQAbpM7TRNkx6XusYrO

우리의 거대한 시간 초과 실행을 수행하십시오 testfile:

이제 두 명령을 사용하여 단일 시간 실행을 수행하여 작업중 인 크기를 추정 해 봅시다.

$ time sed '1d' testfile > /dev/null
real    0m2.104s
user    0m1.944s
sys     0m0.156s

$ time tail -n +2 testfile > /dev/null
real    0m0.181s
user    0m0.044s
sys     0m0.132s

우리는 이미 큰 파일에 대한 정말 명확한 결과가 참조 tail크기보다 더 빨리이다 sed. 그러나 재미를 위해 큰 차이를 만드는 임의의 부작용이 없는지 확인하려면 100 번 수행하십시오.

$ time for i in {1..100}; do sed '1d' testfile > /dev/null; done
real    3m36.756s
user    3m19.756s
sys     0m15.792s

$ time for i in {1..100}; do tail -n +2 testfile > /dev/null; done
real    0m14.573s
user    0m1.876s
sys     0m12.420s

결론은 동일하게 유지되며 sed큰 파일의 첫 번째 줄을 제거하는 것은 비효율적 tail입니다.

그리고 그렇습니다 .Bash의 루프 구조가 느리다는 것을 알고 있지만 여기서는 반복을 거의 수행하지 않으며 일반 루프가 걸리는 시간은 어쨌든 sed/ tail런타임 과 비교하여 중요하지 않습니다 .

작은 파일 타이밍 :

작은 설정 testfile:

이제 완성도를 높이기 위해 kB 범위에 작은 입력 파일이있는 더 일반적인 경우를 살펴 보겠습니다. 다음 numoflines=100과 같이 임의의 입력 파일을 만들어 봅시다 :

$ wc -l testfile 
100 testfile

$ du -h testfile 
8,0K    testfile

$ head -n 3 testfile 
tYMWxhi7GqV0DjWd
pemd0y3NgfBK4G4ho/
aItY/8crld2tZvsU5ly

우리의 작은 시간에 실행을 실행하십시오 testfile:

이러한 작은 파일의 타이밍이 경험에서 몇 밀리 초 범위에있을 것으로 예상 할 수 있으므로 즉시 1000 회 반복하십시오.

$ time for i in {1..1000}; do sed '1d' testfile > /dev/null; done
real    0m7.811s
user    0m0.412s
sys     0m7.020s

$ time for i in {1..1000}; do tail -n +2 testfile > /dev/null; done
real    0m7.485s
user    0m0.292s
sys     0m6.020s

보시다시피, 타이밍은 매우 유사합니다. 해석하거나 궁금해 할 것이 많지 않습니다. 작은 파일의 경우 두 도구가 모두 적합합니다.


답변 해 주셔서 +1 감사합니다. Serg의 의견을 바탕으로 원래 질문 (죄송합니다)을 편집했습니다 awk. 내 원래의 질문은 처음에 찾은 링크를 기반으로했습니다. 나는 제거해야하는 경우 모든 노력 후 조언을 기쁘게 awk만의 독창적 인 프로젝트 범위에 대한 해결책 후보 및 반환 초점으로 sed하고 tail.
WinEunuuchs2Unix

이것은 어떤 시스템입니까? 내 Mac (그래서 BSD 도구)에서 / usr / share / dict / words 테스트하면 sed는 0.09s awk 'NR > 1', 꼬리는 0.19s (그리고 흥미롭게도)가됩니다.
케빈

5

bash 내장을 사용하는 또 다른 대안은 다음과 cat같습니다.

{ read ; cat > headerless.txt; } < $file

$file{ }명령 그룹 으로 리디렉션됩니다 . read단순히 읽고 첫 번째 줄을 삭제합니다. 그런 다음 나머지 스트림을 파이프 cat하여 대상 파일에 씁니다.

내 우분투 16.04에서 이것과 tail솔루션 의 성능 은 매우 비슷합니다. 나는 seq다음 과 같이 지연 테스트 파일을 만들었습니다 .

$ seq 100000000 > 100M.txt
$ ls -l 100M.txt 
-rw-rw-r-- 1 ubuntu ubuntu 888888898 Dec 20 17:04 100M.txt
$

tail 해결책:

$ time tail -n +2 100M.txt > headerless.txt

real    0m1.469s
user    0m0.052s
sys 0m0.784s
$ 

cat/ brace 솔루션 :

$ time { read ; cat > headerless.txt; } < 100M.txt 

real    0m1.877s
user    0m0.000s
sys 0m0.736s
$ 

나는 현재 Ubuntu VM을 편리하게 사용할 수 있으며 모두 동일한 야구장에 있지만 두 타이밍의 상당한 변화를 보았습니다.


1
답변 +1 감사합니다. 그것은 매우 흥미로운 해결책이며 괄호와 bash의 계층 순서를 통해 오른쪽에서 왼쪽으로 읽는 것을 좋아합니다. (내가 올바르게 말했는지 확실하지 않습니다). 입력 파일의 크기와 타이밍 벤치 마크 결과로 답변을 업데이트하기가 가능합니까?
WinEunuuchs2Unix

@ WinEunuuchs2Unix Timings는 VM에 있기 때문에 신뢰할 수는 없지만 추가했습니다. 지금은 베어 메탈 우분투 설치가 없습니다.
Digital Trauma

어쨌든 VM과 VM을 비교할 때 VM과 Bare Metal이 중요하다고 생각하지 않습니다. 타이밍 증명 감사합니다. 나는 아마도 갈 것입니다. tail그러나 read옵션이 매우 멋지다고 생각합니다 .
WinEunuuchs2Unix

4

내 시스템에서 시도하고 각 명령 앞에 접두사를 붙이면 time다음과 같은 결과가 나타납니다.

sed :

real    0m0.129s
user    0m0.012s
sys     0m0.000s

꼬리 :

real    0m0.003s
user    0m0.000s
sys     0m0.000s

내 시스템에서 우분투 16.04를 실행하는 AMD FX 8250 이상은 꼬리가 훨씬 빠릅니다. 테스트 파일의 크기는 540k 인 10,000 행입니다. HDD에서 파일을 읽었습니다.


답변 해 주셔서 +1 감사합니다. AU Chatroom에서 별도의 테스트에서 한 사용자가 61MB 파일이있는 RAMDisk를 사용하면 tail이 sed (21.86 초)보다 10 배 빠릅니다 (2.31 초). 코드 블록을 적용하기 위해 답을 편집했지만 사용한 파일 크기로 편집 할 수도 있습니다.
WinEunuuchs2Unix

@Serg 이것은 단지 일화적인 대답 일 뿐이며, 다른 하드웨어 구성, 다른 테스트 파일 등으로 다른 결과를 얻을 수 있다는 것은 당연합니다.
Nick Sillito

2
캐시에없는 파일 sed은 사용시이 결과에 영향을 줄 수 있습니다. 테스트 한 순서입니다.
Minix

어떤 종류의 시스템입니까? 여기에 다른 게시물에 대해 언급 한 것처럼 내 Mac의 sed속도는 약 두 배 빠릅니다.
케빈

1

때문에 더 나은 어떤 말을 객관적인 방법이 없다 sed하고 tail있는 유일한 일이없는 프로그램 실행 중에 시스템에서 실행하는 것이. 디스크 i / o, 네트워크 i / o, 우선 순위가 높은 프로세스의 CPU 인터럽트와 같은 많은 요소가 프로그램 실행 속도에 영향을줍니다.

둘 다 C로 작성되었으므로 언어 ​​문제가 아니라 환경 문제입니다. 예를 들어, SSD를 가지고 있으며 시스템에 마이크로 초 단위의 시간이 걸리지 만 하드 드라이브의 동일한 파일의 경우 HDD 속도가 상당히 느려 시간이 더 걸립니다. 하드웨어도 마찬가지입니다.

선택할 명령을 고려할 때 명심해야 할 몇 가지 사항이 있습니다.

  • 당신의 목적은 무엇입니까? sed텍스트를 변환하기위한 스트림 편집기입니다. tail특정 텍스트 줄을 출력하기위한 것입니다. 줄을 다루고 인쇄 만하려면을 사용하십시오 tail. 텍스트를 편집하려면을 사용하십시오 sed.
  • tail보다 구문이 훨씬 간단 sed하므로 읽을 수있는 것과 다른 사람이 읽을 수있는 것을 사용하십시오.

또 다른 중요한 요소는 처리중인 데이터의 양입니다. 작은 파일은 성능 차이를 제공하지 않습니다. 큰 파일을 다룰 때 그림이 재미있어집니다. 2GB BIGFILE.txt를 사용하면 sed보다 많은 시스템 호출이 tail있고 상당히 느리게 실행되는 것을 볼 수 있습니다 .

bash-4.3$ du -sh BIGFILE.txt 
2.0G    BIGFILE.txt
bash-4.3$ strace -c  sed '1d' ./BIGFILE.txt  > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 59.38    0.079781           0    517051           read
 40.62    0.054570           0    517042           write
  0.00    0.000000           0        10         1 open
  0.00    0.000000           0        11           close
  0.00    0.000000           0        10           fstat
  0.00    0.000000           0        19           mmap
  0.00    0.000000           0        12           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         2           rt_sigaction
  0.00    0.000000           0         1           rt_sigprocmask
  0.00    0.000000           0         1         1 ioctl
  0.00    0.000000           0         7         7 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           getrlimit
  0.00    0.000000           0         2         2 statfs
  0.00    0.000000           0         1           arch_prctl
  0.00    0.000000           0         1           set_tid_address
  0.00    0.000000           0         1           set_robust_list
------ ----------- ----------- --------- --------- ----------------
100.00    0.134351               1034177        11 total
bash-4.3$ strace -c  tail  -n +2 ./BIGFILE.txt  > /dev/null
% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 62.30    0.148821           0    517042           write
 37.70    0.090044           0    258525           read
  0.00    0.000000           0         9         3 open
  0.00    0.000000           0         8           close
  0.00    0.000000           0         7           fstat
  0.00    0.000000           0        10           mmap
  0.00    0.000000           0         4           mprotect
  0.00    0.000000           0         1           munmap
  0.00    0.000000           0         3           brk
  0.00    0.000000           0         1         1 ioctl
  0.00    0.000000           0         3         3 access
  0.00    0.000000           0         1           execve
  0.00    0.000000           0         1           arch_prctl
------ ----------- ----------- --------- --------- ----------------
100.00    0.238865                775615         7 total

답변 해 주셔서 +1 감사합니다. 그러나이 의견이 어떤 명령을 사용
해야할지

@ WinEunuuchs2Unix 글쎄, 당신은 어떤 명령이 더 나은지 물었습니다. 그래서 나는 그 질문에 정확하게 대답하고 있습니다. 어느 명령을 선택할지는 당신에게 달려 있습니다. tail보다 잘 읽을 수 있다면 sed사용하십시오. 복잡하게 될 수 있기 때문에 개인적으로 python또는 awk오히려 사용 sed하려고합니다. 또한 성능에 관심이 있다면 현실을 직시하자. 여기에서 마이크로 초 단위의 결과를 볼 수있다. 읽으려고하는 기가 바이트 범위의 엄청나게 큰 파일이 아니라면 차이를 느끼지 않을 것입니다.
Sergiy Kolodyazhnyy

오, 나도 awk대답 을 주셔서 감사합니다 :) ... 내 질문은 다른 AU Q & A (링크)를 기반으로했으며 거기에서 언급하지 않았습니다 awk. 작은 파일에서 시차가 공칭임을 동의합니다. 나는 좋은 습관을 기르려고 노력했습니다.
WinEunuuchs2Unix

1
@ WinEunuuchs2Unix 물론 awk 'NR!=1' input_file.txt 입니다. 그것은 나에게 약 150 밀리 초, 모두 같은 수의 동등하게 같은 결과를 제공 tailsed. 그러나 agian, 나는 SSD를 사용하고 있으므로 명령이 아니라 하드 드라이브와 CPU라고 말하고 싶습니다.
Sergiy Kolodyazhnyy 2016

1
@Serg는 1M 라인을 포함하는 60MB 파일 만 있어도 1000 sed분은 3 분 이상 걸리지 tail만 약 20 초만 필요합니다. 그건 아닌 기가 바이트 범위에서 확실히, 아직 실제로 크지 않다.
바이트 사령관

1

최고 답변은 디스크를 고려하지 않았습니다. > /dev/null

큰 파일이 있고 디스크에 임시 복제본을 만들지 않으려는 경우 vim -c

$ cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n 10000000 > testfile
$ time sed -i '1d' testfile

real    0m59.053s
user    0m9.625s
sys     0m48.952s

$ cat /dev/urandom | base64 -w0 | tr 'n' '\n'| head -n 10000000 > testfile
$ time vim -e -s testfile -c ':1d' -c ':wq'

real    0m8.259s
user    0m3.640s
sys     0m3.093s

편집 : 파일이 사용 가능한 메모리보다 큰 경우 vim -c작동하지 않는 경우 파일을 증분로드 할만 큼 똑똑하지 않은 것처럼 보입니다.


0

다른 답변은 첫 줄이 누락 된 새 파일을 만드는 것이 더 좋은 것을 잘 보여줍니다. 새 파일을 만드는 대신 파일을 편집하려면 새 파일을 만들지 ed않아야하므로 더 빠릅니다. 그러나 ed한 번만 사용했기 때문에 줄을 제거하는 방법을 검색해야합니다 .

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