В этом ответе (Как я могу удалить первую строку файла с sed?) существует два способа удалить первую запись в файле:
sed '1d' $file >> headerless.txt
**----------------ИЛИ----------------**
tail -n +2 $file >> headerless.txt
Лично я думаю tail
опция косметически более приятна и более читаема, но вероятно потому что мне sed-бросают-вызов.
Какой метод является самым быстрым?
sed
по сравнению с. tail
удалить первую строку файла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
Как Вы видите, синхронизации весьма схожи, нет очень, чтобы интерпретировать или задаться вопросом о. Для маленьких файлов одинаково хорошо подходят оба инструмента.
Попробовав в моей системе и поставив перед каждой командой префикс 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 КБ. Файл был прочитан с жесткого диска.
Другие ответы показывают хорошо, что лучше для создания нового файла с первыми пропавшими без вести строки. Если Вы хотите отредактировать файл в противоположность, создают новый файл, хотя, я держал пари ed
, будет быстрее, потому что он не должен создавать новый файл вообще. Но необходимо искать, как удалить строку с ed
, потому что я использовал ее только однажды.
Главный ответ не взял диск, во внимание делающий > /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
не работает, похож на не достаточно умный, чтобы сделать возрастающую загрузку файла
Вот другая альтернатива, использование просто колотит 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, удобный прямо сейчас, хотя, и видел значительную вариацию в синхронизациях обоих, хотя они - все на той же приблизительной оценке.
Нет никакого объективного способа сказать, который лучше, потому что 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