Bash вывести файл без первой строки
Мне нужно несколько раз удалить первую строку из огромного текстового файла с помощью сценария bash.
Сейчас я использую sed -i -e "1d" $FILE , но на удаление уходит около минуты.
Есть ли более эффективный способ добиться этого?
Tail НАМНОГО МЕДЛЕЕ, чем sed. tail требуется 13,5 секунды, sed - 0,85 секунды. В моем файле ~ 1 млн строк, ~ 100 МБ. MacBook Air 2013 с SSD.
-n x : просто выведите последние x строк. tail -n 5 даст вам последние 5 строк ввода. Знак + инвертирует аргумент и заставляет tail печатать что угодно, кроме первых строк x-1 . tail -n +1 напечатает весь файл, tail -n +2 все, кроме первой строки и т. Д.
GNU tail намного быстрее, чем sed . tail также доступен в BSD, и флаг -n +2 согласован в обоих инструментах. Проверьте FreeBSD или OS X для получения дополнительной информации.
Однако версия BSD может быть намного медленнее, чем sed . Интересно, как им это удалось; tail должен просто читать файл построчно, в то время как sed выполняет довольно сложные операции, включая интерпретацию сценария, применение регулярных выражений и тому подобное.
Примечание: у вас может возникнуть соблазн использовать
Но это даст вам пустой файл . Причина в том, что перенаправление ( > ) происходит до того, как tail будет вызван оболочкой:
- Shell обрезает файл $FILE
- Shell создает новый процесс для tail
- Shell перенаправляет стандартный вывод процесса tail на $FILE
- tail читает из теперь пустого $FILE
Если вы хотите удалить первую строку внутри файла, вы должны использовать:
&& гарантирует, что файл не будет перезаписан при возникновении проблемы.
Согласно этому ss64.com/bash/tail.html типичный буфер по умолчанию равен 32 КБ при использовании BSD "хвост" с опцией -r . Может где-то в системе есть настройка буфера? Или -n - 32-битное число со знаком?
@Eddie: user869097 сказал, что это не работает, когда одиночная строка составляет 15 МБ или больше. Пока строки короче, tail будет работать с файлом любого размера.
- на странице руководства: -n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Я собирался согласиться с @JonaChristopherSahnwaldt - tail намного медленнее, чем вариант sed, на порядок. Я тестирую его на файле размером 500 000К строк (не более 50 символов в строке). Однако потом я понял, что использую версию tail для FreeBSD (которая по умолчанию поставляется с OS X). Когда я переключился на GNU tail, хвостовой вызов был в 10 раз быстрее, чем вызов sed (и вызов sed GNU тоже). Аарон Дигулла здесь прав, если вы используете GNU.
Для тех, кто использует SunOS, которая не является GNU, следующий код поможет:
Нет, это настолько эффективно, насколько вы собираетесь получить. Вы могли бы написать программу на C, которая могла бы выполнять работу немного быстрее (меньше времени запуска и обработки аргументов), но она, вероятно, будет стремиться к той же скорости, что и sed, когда файлы становятся большими (и я предполагаю, что они большие, если это займет минуту ).
Но ваш вопрос страдает той же проблемой, что и многие другие, поскольку предполагает решение. Если бы вы подробно рассказали нам что вы пытаетесь сделать, а не как , мы, возможно, сможем предложить лучший вариант.
Например, если это файл A, который обрабатывает какая-то другая программа B, одним из решений было бы не удалять первую строку, а изменить программу B, чтобы обработать ее по-другому.
Допустим, все ваши программы присоединяются к этому файлу A, а программа B в настоящее время читает и обрабатывает первую строку перед ее удалением.
Вы можете перепроектировать программу B так, чтобы она не пыталась удалить первую строку, но сохраняла постоянное (вероятно, файловое) смещение в файле A, чтобы при следующем запуске она могла искать это смещение, обрабатывать там строку и обновите смещение.
Затем, в тихое время (в полночь?), Он мог бы выполнить специальную обработку файла A, чтобы удалить все обрабатываемые в данный момент строки и установить смещение обратно на 0.
Программа определенно будет быстрее открывать и искать файл, чем открывать и перезаписывать. Это обсуждение, конечно, предполагает, что вы контролируете программу B. Я не знаю, так ли это, но могут быть другие возможные решения, если вы предоставите дополнительную информацию.
Я думаю, что OP пытается достичь того, что заставило меня найти этот вопрос. У меня есть 10 файлов CSV по 500 тыс. Строк в каждом. Каждый файл имеет ту же строку заголовка, что и первая строка. Я кошку: помещаю эти файлы в один файл, а затем импортирую их в БД, позволяя БД создавать имена столбцов из первой строки. Очевидно, я не хочу, чтобы эта строка повторялась в файле 2-10.
Нужно вывести все содержимое файла до первого появления данной строки (надо вывести, включая саму строку).
А как вывести все содержимое файла после первого появления искомой строки? (надо вывести, исключая саму строку).
blexey ★★★★★ ( 04.07.20 15:07:28 )
Последнее исправление: blexey 04.07.20 15:09:19 (всего исправлений: 1)
только возможно надёжнее будет ^---$ .
тс, ты теперь должен ведьмаку звезду. не стыдно тебе с пятью звёздами такие вопросы задавать?
лор исправил + на буллет, собака
Костыльный вариант с grep:
crutch_master ★★★★★ ( 04.07.20 15:24:06 )
Последнее исправление: crutch_master 04.07.20 15:25:37 (всего исправлений: 2)
Ага, сделал вот так:
ты теперь должен ведьмаку звезду. не стыдно тебе с пятью звёздами такие вопросы задавать?
Абсолютно не стыдно, я до bash добираюсь раз в несколько лет, и очень этому рад.
Вообще, ты больной человек с явными психическими девиациями. Нормальному человеку совершенно не стыдно спрашивать то, что он не знает. Или то, что знает, но не допонимает. Или хочет услышать мнение коллег. Это называется развитие. Тот, кто сидит и боится задать лишний вопрос, чтобы окружающие не дай бог не подумали что человек чего-то не знает, например ты, называется задротом. Задрот может быть хорошим специалистом, обычно в узкой области, но усилия, которыми он этого добивается, очень непроизводительны. Задрот сам себе искусственно или в силу врожденных причин, ограничивает себе развитие.
Невозможно по книгам и интернету хорошо разобраться со сложными концепциями в отрыве от общества. Мало того, задрот обычно обеспечивается окружающим обществом в своем существовании: ему, по сути, создают искусственный источник дохода. И эта тварина этот доход непроизводительно проедает: в первый раз когда вместо быстрого докапывания до сути, задродствует в одиночку, второй раз - когда скрывает свои знания и вместо быстрой помощи другим людям, исходит на них желчью. Третий раз - когда рассказывает что задавать вопросы - это стыдно, желая распространить свое задродство на других. В общем, задрот - это не просто бесполезное существо, но и паразит на теле общества.
Мне нужно повторно удалить первую строку из огромного текстового файла с помощью скрипта bash.
сейчас я использую sed -i -e "1d" $FILE - но для удаления требуется около минуты.
есть ли более эффективный способ сделать это?
-n x : просто распечатайте последний x строки. tail -n 5 даст вам последние 5 строк ввода. The + знак вида инвертирует аргумент и делает tail печать ничего, кроме первого x-1 строки. tail -n +1 напечатал бы весь файл, tail -n +2 все, кроме первой строки, и т. д.
GNU tail гораздо быстрее, чем sed . tail также доступно на BSD и -n +2 флаг согласовано в обоих инструментах. Проверьте FreeBSD или OS X man-страницы для более.
версия BSD может быть намного медленнее, чем sed , хотя. Интересно, как им это удалось?--7--> надо просто читать файл построчно, пока sed выполняет довольно сложные операции, связанные с интерпретацией скрипта, применением регулярных выражений и тому подобное.
Примечание: у вас может возникнуть искушение использовать
но это даст вам пустой файл. Причина в том, что перенаправление ( > ) происходит перед tail вызывается оболочкой:
- оболочка усекает файл $FILE
- Shell создает новый процесс для tail
- Shell перенаправляет stdout
вы можете использовать-i для обновления файла без использования оператора'>'. Следующая команда удалит первую строку из файла и сохранит ее в файле.
для тех, кто находится на SunOS, который не является GNU, следующий код поможет:
нет, это примерно так же эффективно, как вы собираетесь получить. Вы можете написать программу на C, которая может выполнять работу немного быстрее (меньше времени запуска и обработки аргументов), но она, вероятно, будет стремиться к той же скорости, что и sed, поскольку файлы становятся большими (и я предполагаю, что они большие, если это займет минуту).
но ваш вопрос страдает от той же проблемы, что и многие другие, поскольку он заранее предполагает решение. Если бы вы рассказали нам подробно что вы пытаетесь делай, а не то как, мы можем предложить лучший вариант.
например, если это файл A, который обрабатывает другая программа B, одним из решений было бы не удалять первую строку, а изменять программу B для ее обработки по-другому.
предположим, что все ваши программы добавляются в этот файл A и программа B в настоящее время читает и обрабатывает первую строку перед ее удалением.
вы можете перепроектировать программу B, чтобы она не пыталась удалить первая строка, но поддерживает постоянное (возможно, файловое) смещение в файл A, чтобы при следующем запуске он мог искать это смещение, обрабатывать строку там и обновлять смещение.
затем, в спокойное время (полночь?), он может выполнить специальную обработку файла A, чтобы удалить все строки, обрабатываемые в настоящее время, и установить смещение обратно в 0.
Это, безусловно, будет быстрее для программы, чтобы открыть и искать файл, а не открывать и переписывать. Это обсуждение предполагает вас контролировать программу Б, конечно. Я не знаю, так ли это, но могут быть другие возможные решения, если вы предоставите дополнительную информацию.
вы can редактировать файлы на месте: просто используйте perl -i флаг, как это:
Это заставляет первую строку исчезнуть, как вы просите. Perl нужно будет прочитать и скопировать весь файл, но он организует для вывода, который будет сохранен под именем исходного файла.
Как сказал Пакс, вы, вероятно, не получите быстрее, чем это. Причина в том, что практически нет файловых систем, поддерживающих усечение с начала файла, поэтому это будет O ( n операции), где n размер файла. Что вы можете сделать много быстрее, хотя перезаписывает первую строку с тем же количеством байтов (возможно, с пробелами или комментарием), которые могут работать для вас в зависимости от того, что вы пытаетесь сделать (что это, кстати?).
У меня есть текстовый файл и я хочу удалить первую строку (заголовок), чтобы прочитать файл без заголовка в конвейер. Это кажется тривиальным вопросом, на который много раз отвечали, но из-за размера файлов, с которыми я сталкивался, решения, которые я нашел до сих пор, не работали. Для моих тестовых прогонов я использовал echo "$(tail -n +2 "$FILE_NAME")" > "$FILE_NAME" , но выполнение этого с моим большим файлом приводит к следующей ошибке: bash: xrealloc: cannot allocate 18446744071562067968 bytes (1679360 bytes allocated) Есть ли какой-либо метод, который редактирует файл на месте? Загрузка их в память не будет работать, некоторые из моих файлов имеют размер до 400 Гб. Спасибо за помощь!
4 ответа
Вы можете использовать такой код:
Это отправит в выходной файл все, кроме первой строки. Вы можете использовать эту конструкцию для выполнения своих операций:
Изменение вашей команды таким образом может сделать работу:
Это потребует двойного дискового пространства
Я просто собираюсь затронуть часть вопроса «отредактировать файл на месте», хотя, похоже, это не совсем то, что вы искали. Вы найдете множество решений, описывающих функции, которые, как утверждают, выполняют редактирование на месте, но обычно эти решения вообще не редактируют файл. Вместо этого они записывают во временный файл, а затем перезаписывают оригинал временным файлом. (например, sed --in-place является распространенным решением, которое записывает во временный файл). Редактирование файла на месте - это то, что вы практически никогда не хотите делать, поскольку изменение файла опасно. Действительно, если вы считаете, что хотите отредактировать файл на месте, серьезно подумайте и предположите, что вы не правы. Однако, если по какой-то причине вам действительно нужно это сделать, возможно, безопаснее всего это сделать:
Будучи явным, довольно ясно, что вы можете легко потерять данные в файле. Но если вы хотите избежать чтения всего файла в память или не иметь двух копий на нескольких носителях одновременно, нет способа избежать этого, и любое решение, скрывающее этот риск, обманывает вас. Так что делать это явно и знать, где находятся опасности, - это то, что нужно делать.
Он запускается sed со скриптом verysimple 1d , который выбирает первую строку (селектор 1 ) и удаляет ее (команда d ). Благодаря опции на месте -i ваш файл будет перезаписан без использования промежуточного файла.
Даже если вы не беспокоитесь о промежуточном файле, sed использует его собственный промежуточный файл внутри. Во время этой операции ваш диск будет страдать вдвое больше размера файла.
Хвост достаточно эффективен для этой операции.
Проблема в том, что вы хотите перезаписать исходный файл.
Когда sed используется в режиме перезаписи, он делает именно это (для чего-либо в течение нескольких строк).
У меня очень длинный файл, который я хочу напечатать, но пропускаю первые строки 1e6, например. Я смотрю на страницу cat man, но я не видел никакой возможности сделать это. Я ищу команду для этого или простую программу bash.
вам понадобится хвост.
Если вам действительно нужно пропустить определенное количество строк, используйте
то есть, если вы хотите пропустить N строк, вы начинаете печатать строку N+1. Пример:
если вы хотите просто увидеть последние столько строк, опустите"+":
Если у вас есть GNU tail, доступный в вашей системе, вы можете сделать следующее:
Это + символ, который делает то, что вы хотите. Цитата из man-страницы:
Если первый символ K (количество байтов или строк) равен a '+', печать, начиная с k-го элемента с начала каждого файла.
таким образом, как отмечено в комментарии, putting +1000001 начинает печать с первого элемента после первого 1,000,000 русло.
самый простой способ удалить первые десять строк файла:
менее многословная версия с AWK:
но я бы рекомендовал использовать целые числа.
просто предложить sed альтернативы. :) Чтобы пропустить первый миллион строк, попробуйте |sed '1,1000000d' .
Если вы хотите увидеть первую строку 10, вы можете использовать sed, как показано ниже:
или если вы хотите видеть линии от 20 до 30 вы можете использовать:
Если вы хотите пропустить первые две строки
tail -n +3
Если вы хотите пропустить первую строку x
tail -n +$((x+1))
этот скрипт отлично работает для меня:
используется с этим образцом файла (file.txt):
команда (она будет извлекаться со второй по четвертую строку в файле):
вывод этой команды:
конечно, вы можете улучшить его, например, проверив, что все значения аргументов являются ожидаемыми : -)
кроме того, если вы хотите напечатать только известный диапазон, используйте команду print с -n флаг:
это решение должно надежно работать на всех системах UNIX, независимо от наличия утилит GNU.
Читайте также: