Который быстрее для удаления первой строки в файле … sed или хвост?

В этом ответе (Как я могу удалить первую строку файла с sed?) существует два способа удалить первую запись в файле:

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

**----------------ИЛИ----------------**

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

Лично я думаю tail опция косметически более приятна и более читаема, но вероятно потому что мне sed-бросают-вызов.

Какой метод является самым быстрым?

14
задан 13 April 2017 в 05:25

6 ответов

Производительность sed по сравнению с. tail удалить первую строку файла

TL; DR

  • sed очень мощно и универсален, но это - то, что заставляет его замедлиться, специально для больших файлов со многими строками.

  • tail делает всего одну простую вещь, но что один она преуспевает и быстро, даже для больших файлов со многими строками.

Для малых и средних файлов, sed и tail работают столь же быстро (или медленные, в зависимости от Ваших ожиданий). Однако для больших входных файлов (несколько MBS), различие в производительности значительно растет (порядок величины для файлов в диапазоне сотен MBS), с tail ясно поражение sed.

Эксперимент

Общие приготовления:

Наши команды для анализа:

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

Обратите внимание, что я передаю вывод по каналу к /dev/null каждый раз для устранения терминального вывода или файла пишет как узкое место производительности.

Давайте настроим псевдодиск для устранения диска ввод-вывод как потенциальное узкое место. У меня лично есть a tmpfs смонтированный в /tmp таким образом, я просто поместил мой testfile там для этого эксперимента.

Затем я однажды создаю случайный тестовый файл, содержащий указанную сумму строк $numoflines со случайной длиной строки и случайными данными с помощью этой команды (отмечают, что это определенно не оптимально, это становится действительно медленным для приблизительно> 2M строки, но кто заботится, это не вещь, которую мы анализируем):

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

О, btw. мой тестовый ноутбук работает, Ubuntu 16.04, 64 обдумала ЦП Intel i5-6200U. Только для сравнения.

Синхронизация больших файлов:

Установка огромного testfile:

Выполнение команды выше с numoflines=10000000 произведенный случайный файл, содержащий 10M строки, занимая более чем 600 МБ - это довольно огромно, но давайте запустимся с него, потому что мы можем:

$ 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:

Теперь для полноты, давайте посмотрим на более общий падеж, что у Вас есть маленький входной файл в диапазоне КБ. Давайте создадим случайный входной файл с numoflines=100, сходство с этим:

$ wc -l testfile 
100 testfile

$ du -h testfile 
8,0K    testfile

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

Выполните синхронизированное выполнение с нашим маленьким testfile:

Поскольку мы можем ожидать, что синхронизации для таких маленьких файлов будут в диапазоне нескольких миллисекунд на основе опыта, позвольте нам просто сделать 1 000 повторений сразу же:

$ 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

Как Вы видите, синхронизации весьма схожи, нет очень, чтобы интерпретировать или задаться вопросом о. Для маленьких файлов одинаково хорошо подходят оба инструмента.

28
ответ дан 23 November 2019 в 02:53

Попробовав в моей системе и поставив перед каждой командой префикс time, я получил следующие результаты:

sed:

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

и tail:

real    0m0.003s
user    0m0.000s
sys     0m0.000s
[ 116], что говорит о том, что на моей системе, по крайней мере, AMD FX 8250 с Ubuntu 16.04, tail значительно быстрее. Тестовый файл имел 10 000 строк размером 540 КБ. Файл был прочитан с жесткого диска.

4
ответ дан 23 November 2019 в 02:53

Другие ответы показывают хорошо, что лучше для создания нового файла с первыми пропавшими без вести строки. Если Вы хотите отредактировать файл в противоположность, создают новый файл, хотя, я держал пари ed, будет быстрее, потому что он не должен создавать новый файл вообще. Но необходимо искать, как удалить строку с ed, потому что я использовал ее только однажды.

0
ответ дан 23 November 2019 в 02:53

Главный ответ не взял диск, во внимание делающий > /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 не работает, похож на не достаточно умный, чтобы сделать возрастающую загрузку файла

1
ответ дан 23 November 2019 в 02:53

Вот другая альтернатива, использование просто колотит builtins и cat:

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

$file перенаправляется в { } группировка команды. read просто чтения и отбрасывания первая строка. Остальная часть потока затем передается по каналу к cat который пишет это в целевой файл.

На моей Ubuntu 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/ заключают в фигурные скобки решение:

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

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

У меня только есть VM Ubuntu, удобный прямо сейчас, хотя, и видел значительную вариацию в синхронизациях обоих, хотя они - все на той же приблизительной оценке.

5
ответ дан 23 November 2019 в 02:53

Нет никакого объективного способа сказать, который лучше, потому что sed и tail не единственные вещи, которые работают на системе во время выполнения программы. Много факторов, таких как диск i/o, сеть i/o, прерывания ЦП для более высоких приоритетных процессов - все, на что они влияют, как быстро Ваша программа будет работать.

Они оба записаны в C, таким образом, это не проблема языка, но больше экологической. Например, у меня есть SSD, и в моей системе это займет время в микросекундах, но для того же файла на жестком диске потребуется больше времени, потому что жесткие диски значительно медленнее. Таким образом, аппаратные средства играют роль в этом, также.

Существует несколько вещей, которые можно хотеть иметь в виду при рассмотрении который команда выбрать:

  • Какова Ваша цель? sed потоковый редактор для преобразования текста. tail для вывода определенных строк текста. Если Вы хотите иметь дело со строками и только распечатать их, использовать tail. Если Вы хотите отредактировать текст, использовать sed.
  • tail имеет намного более простой синтаксис, чем sed, так используют то, что можно считать себя и что могут считать другие.

Другим важным фактором является объем данных, который Вы обрабатываете. Маленькие файлы не дадут Вам различия в производительности. Изображение становится интересным, когда Вы имеете дело с большими файлами. С BIGFILE.txt на 2 ГБ мы видим это 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
ответ дан 23 November 2019 в 02:53

Другие вопросы по тегам:

Похожие вопросы: