Скажем , у меня есть огромный текстовый файл (> 2 Гб) , и я просто хочу cat
линии X
к Y
(например , 57890000 на 57890010).
Из того, что я понимаю, я могу сделать это, подключившись head
к сети tail
или наоборот, т.е.
head -A /path/to/file | tail -B
или альтернативно
tail -C /path/to/file | head -D
где A
, B
, C
и D
могут быть вычислены из числа строк в файле, X
и Y
.
Но есть две проблемы с этим подходом:
- Вы должны вычислить
A
,B
,C
иD
. - Команды могут передавать
pipe
друг другу намного больше строк, чем мне интересно читать (например, если я читаю всего несколько строк в середине огромного файла)
Есть ли способ заставить оболочку просто работать и выводить нужные мне строки? (предоставляя только X
а Y
)?
tail
cat
large-files
head
Амелио Васкес-Рейна
источник
источник
Ответы:
Я предлагаю
sed
решение, но ради полноты,Вырезать после последней строки:
Тест скорости:
seq 100000000 > test.in
real
время, как сообщаетbash
встроенныйtime
Это ни в коем случае не точные тесты, но разница ясна и достаточно повторяема *, чтобы дать хорошее представление об относительной скорости каждой из этих команд.
*: За исключением между первыми двумя
sed -n p;q
иhead|tail
, которые кажутся по существу одинаковыми.источник
tail -n +50000000 test.in | head -n10
, что в отличие отtail -n-50000000 test.in | head -n10
даст правильный результат?tail+|head
на 10-15% быстрее, чем sed, я добавил этот тест.-c
для пропуска символов,tail+|head
мгновенно. Конечно, вы не можете сказать «50000000», и вам, возможно, придется вручную искать начало раздела, который вы ищете.Если вы хотите, чтобы строки от X до Y включали (начиная с нумерации с 1), используйте
tail
прочтет и откажется от первых строк X-1 (обойти это невозможно), затем прочитает и распечатает следующие строки.head
прочтет и распечатает запрошенное количество строк, затем выйдет. Когдаhead
выходит,tail
получает сигнал SIGPIPE и умирает, поэтому он не будет считывать из входного файла строки размером больше буфера (обычно несколько килобайт).В качестве альтернативы, как предложил gorkypl , используйте sed:
Решение sed значительно медленнее (по крайней мере, для утилит GNU и Busybox; sed может быть более конкурентоспособным, если вы извлекаете большую часть файла в ОС, где скорость передачи данных медленная, а скорость седа). Вот быстрые тесты под Linux; данные были сгенерированы
seq 100000000 >/tmp/a
, среда Linux / amd64,/tmp
tmpfs, и машина в противном случае простаивает и не переставляет.Если вам известен диапазон байтов, с которым вы хотите работать, вы можете извлечь его быстрее, перейдя непосредственно к начальной позиции. Но для строк, вы должны читать с начала и считать новые строки. Чтобы извлечь блоки от x включительно до y эксклюзивно, начиная с 0, с размером блока b:
источник
tail will read and discard the first X-1 line
кажется, избегают, когда число строк дается с конца, В этом случае, хвост, кажется, читает назад с конца в соответствии с временем выполнения. Пожалуйста , прочитайте:http://unix.stackexchange.com/a/216614/79743
.tail
(включая хвост GNU) имеют эвристику для чтения с конца. Это улучшаетtail | head
решение по сравнению с другими методами.head | tail
Подход является одним из лучших и наиболее «идиоматических» способов сделать это:Как отметил Жиль в комментариях, более быстрый путь
Причина, по которой это происходит быстрее, заключается в том, что первым линиям X - 1 не нужно проходить через канал по сравнению с
head | tail
подходом.Ваш вопрос, как сформулированный, немного вводит в заблуждение и, вероятно, объясняет некоторые из ваших необоснованных опасений по поводу этого подхода.
Вы говорите , что вы должны вычислить
A
,B
,C
,D
но , как вы можете видеть, количество строк файла не требуется , и расчет в большинстве 1 необходимо, что оболочка может сделать для вас в любом случае.Вы беспокоитесь, что трубопровод будет читать больше строк, чем необходимо. На самом деле это не так:
tail | head
он настолько эффективен, насколько это возможно с точки зрения файлового ввода-вывода. Во-первых, рассмотрим минимальный объем необходимой работы: чтобы найти X -ю строку в файле, единственный общий способ сделать это - прочитать каждый байт и остановиться, когда вы подсчитываете символы новой строки X, так как нет способа предугадать файл смещение X -й линии. Как только вы достигнете * X * -ой строки, вы должны прочитать все строки, чтобы напечатать их, останавливаясь на Y -й строке. Таким образом, ни один подход не может сойти с рук, читая меньше Y строк. Теперьhead -n $Y
читает не более Yстроки (округлены до ближайшего элемента буфера, но буферы при правильном использовании улучшают производительность, поэтому не нужно беспокоиться об этих издержках). Кроме того,tail
не будет читать больше, чемhead
, поэтому, таким образом, мы показали, чтоhead | tail
читает наименьшее количество возможных строк (опять же, плюс незначительная буферизация, которую мы игнорируем). Единственное преимущество в эффективности подхода с одним инструментом, в котором не используются трубы, - это меньше процессов (и, следовательно, меньше накладных расходов).источник
Наиболее ортодоксальным способом (но не самым быстрым, как отметил Жиль выше) было бы использовать
sed
.В твоем случае:
-n
Вариант подразумевает , что только соответствующие строки печатаются на стандартный вывод.Буква p в конце номера конечной строки означает печать строк в заданном диапазоне. Кв во второй части сценария экономит время, пропуская оставшуюся часть файла.
источник
sed
иtail | head
будет примерно на одном уровне, но оказывается, чтоtail | head
это значительно быстрее (см. Мой ответ ).tail
/head
считаются более "ортодоксальными", поскольку обрезка любого конца файла - это именно то, для чего они созданы. В этих материалахsed
только кажется, что вводится в картину, когда требуются замены - и быстро выталкивается из картинки, когда начинает происходить что-то намного более сложное, поскольку его синтаксис для сложных задач намного хуже, чем AWK, который затем вступает во владение ,Если мы знаем диапазон для выбора, от первой строки:
lStart
до последней строки:lEnd
мы могли бы вычислить:Если мы знаем общее количество строк:
lAll
мы также можем рассчитать расстояние до конца файла:Тогда мы будем знать оба:
Выбор самого маленького из них:
tailnumber
как это:Позволяет нам использовать наиболее быстро выполняемую команду:
Обратите внимание на дополнительный знак плюс («+»), когда
$linestart
выбран.Единственное предостережение в том, что нам нужно общее количество строк, и это может занять некоторое дополнительное время, чтобы найти.
Как обычно с:
Несколько раз измеряются:
Обратите внимание, что времена резко меняются, если выбранные линии находятся в начале или в конце. Команда, которая работает хорошо на одной стороне файла, может быть очень медленной на другой стороне файла.
источник
Я делаю это достаточно часто и поэтому написал этот сценарий. Мне не нужно искать номера строк, скрипт делает все это.
источник
tail|head
, который подробно обсуждался в этом вопросе и других ответах, и 90% определяют номера строк, где появляются указанные строки / шаблоны, что не было частью вопроса . PS вы всегда должны указывать параметры и переменные вашей оболочки; например, «3 доллара» и «4 доллара».