Вывод каждого N-го ряда из большого файла в новый файл

Вопрос или проблема

Вывод каждого N-го ряда из большого файла в новый файл

Я пытаюсь распечатать каждую N-ю строку из файла с более чем 300,000 записей в новый файл. Это должно происходить с каждой N-ой записи, пока не будет достигнут конец файла.

awk 'NR % 5 == 0' input > output

Это выводит каждую пятую строку.

Чтобы использовать переменную окружения:

NUM=5
awk -v NUM=$NUM 'NR % NUM == 0' input > output

Чтобы распечатать каждую N  ю строку, используйте

sed -n '0~Np'

Например, чтобы скопировать каждую 5-ю строку из oldfile в newfile, сделайте

sed -n '0~5p' oldfile > newfile

Это использует sed’s первую~шаг адресную форму,
что означает «сопоставить каждую шаг’ю строку, начиная
с первой строки первой
В теории,
это будет печатать строки 0, 5, 10, 15, 20, 25, … до конца файла.
Конечно, строки 0 не существует, так что печатаются только строки 5, 10, 15, 20, 25, …; 
0~5 – это просто удобный альтернативный способ сказать 5~5
(что печатает каждую 5-ю строку, начиная со строки 5;
т.е. строки 5, 10, 15, 20, 25, …).

Для другого примера этой способности sed
(которая не отвечает на вопрос),

sed -n '2~5p' oldfile

выводил бы строки 2, 7, 12, 17, 22, 27, … до конца файла.

Примечание: этот подход требует GNU sed,
так как первая~шаг адресная форма
является непереносимым расширением.
(Некоторые старые версии GNU sed могут требовать форму 5~5
вместо формы 0~5.)

Вот версия на perl:

perl -ne 'print if $. % 5 == 0;' infile > outfile

Также, аналогично sed, у нас есть awk:

$ seq 1000000000 |awk 'NR==500000{print;exit}'
500000

NR=Номер строки, которую вы хотите распечатать (а затем выходить, чтобы избежать ожидания окончания файла).
В вашем случае

awk 'NR==Nth{print;exit}' inputfile >outputfile

где Nth – это номер N-ой строки, которую вам нужно распечатать.

Я работаю на Mac OS, и у меня возникла следующая ошибка (вероятно, из-за того, что это не GNU sed):

sed: 1: "1~4p": недопустимый код команды ~

К счастью, я смог использовать свои знания vim, чтобы обойти это. Вот что я сделал:

  1. Откройте старый файл и новый файл: vim -p old_file new_file
  2. Переместите курсор к нужной строке, которую нужно распечатать
  3. Нажмите Q дважды, чтобы начать запись макроса (хранится в регистре Q)
  4. Введите следующее: yygtpgt, переместитесь вниз на столько строк, сколько необходимо в старом файле, и когда вы доберетесь до следующей строки, которую хотите распечатать, снова нажмите Q, чтобы остановить запись
    1. Эта последовательность нажатий клавиш срезает текущую строку, переходит к новому файлу и вставляет строку туда, затем возвращается к старому файлу
  5. Запустите макрос столько раз, сколько необходимо. В моем случае, мне нужно было скопировать 44 строки всего, поэтому я запустил оставшиеся 43 раза, нажав: 43@q—то есть запустить макрос, хранящийся в Q, 43 раза
  6. Перейдите к new_file с помощью gt, удалите начальную строку с помощью ggdd и сохраните и выйдите с помощью :wq<Enter>, затем используйте :q<Enter>, чтобы выйти из old_file тоже
  7. Теперь у вас есть new_file только с желаемыми строками, и вы можете продолжать работу с этим файлом—например, cat new_file

Используя Raku (ранее известный как Perl_6)

~$ raku -ne '.put if ++$  % 3 == 0;'  oldfile > newfile

#ИЛИ:

~$ raku -ne '.put if ++$ %% 3;'  oldfile > newfile  

Выше представлены ответы, написанные на Raku, члене семейства языков программирования Perl. Raku создан для работы с Unicode и является хорошим выбором для манипуляции текстовыми файлами и т.д.

  • Первый ответ выше по сути является переводом на Raku отличного ответа @harmic на Perl. В Raku анонимные переменные можно объявлять почти в любом месте: здесь (в сочетании с построчными -ne флагами) используется анонимная счетная переменная ++$ для подсчета строк, начиная с 1 (используйте $++, если хотите начать подсчет с 0). Вместо print в Perl Raku использует $.put или просто .put, что добавляет символ новой строки для вас (put означает распечатать с использованием завершителя.

  • Второй ответ использует новый оператор %% «Делимость» в Raku, который возвращает True, если $a % $b == 0.

Пример входных данных:

0 первая строка записи
1 вторая строка записи
2 третья строка записи
3 первая строка записи
4 вторая строка записи
5 третья строка записи

Пример вывода:

2 третья строка записи
5 третья строка записи

ПРИМЕЧАНИЕ: флаги командной строки в Raku тесно следуют за флагами Perl (например, -pe для поведения, похожего на sed, или -ne для поведения, похожего на awk). Но если вам трудно запомнить флаги, просто используйте -e (выполнить) и рутину lines в Raku, вот так:

~$ raku -e '.put if ++$  % 3 == 0 for lines;'  oldfile > newfile

#ИЛИ:

~$ raku -e '.put if ++$ %% 3 for lines;'  oldfile > newfile  

(Возвращает такой же вывод, как выше).

https://docs.raku.org/language/operators#infix_%
https://docs.raku.org/language/operators#infix_%%
https://raku.org

Ответ или решение

Для того чтобы вывести каждую N-ю строку из большого файла и записать их в новый файл, вы можете воспользоваться несколькими подходами с помощью стандартных инструментов UNIX/Linux. В зависимости от ваших предпочтений и доступных утилит, вы можете использовать awk, sed, perl или даже raku. Ниже приведены примеры для каждого из этих инструментов.

Использование awk

awk — это мощный текстовый процессор, который идеально подходит для обработки текстовых файлов. Чтобы вывести каждую N-ю строку, используйте следующую команду:

NUM=5 # замените 5 на нужное вам N
awk -v NUM="$NUM" 'NR % NUM == 0' input.txt > output.txt

В этом примере переменная NUM определяет, какие строки будут выведены. Если NUM равно 5, команда выведет каждую пятую строку из файла input.txt в файл output.txt.

Использование sed

sed также является мощным инструментом для обработки текста. Чтобы вывести каждую N-ю строку, выполните следующую команду:

sed -n '0~5p' oldfile > newfile

Здесь 0~5 означает выводить каждую пятую строку, начиная с нулевой. Хотя первая строка в файле фактически отсутствует, потому что строки считаются с 1, таким образом, будет выведена строка 5, 10, 15 и т.д.

Использование perl

Если вам более удобен perl, вы можете сделать это следующим образом:

perl -ne 'print if $. % 5 == 0;' infile > outfile

Здесь $. — это текущий номер строки. Эта команда выведет каждую пятую строку из файла infile в файл outfile.

Использование raku

Если вы предпочитаете язык raku, вы можете воспользоваться следующими командами:

raku -ne '.put if ++$ % 5 == 0;' oldfile > newfile

Или:

raku -ne '.put if ++$ %% 5;' oldfile > newfile

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

Обработка больших файлов

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

Вывод

Выбор инструмента зависит от ваших предпочтений и доступных утилит в вашей среде. Все вышеперечисленные команды позволяют эффективно и быстро извлекать нужные строки из файла. Убедитесь, что вы заменяете input.txt, oldfile, infile и другие названия файлов на те, которые соответствуют вашему контексту.

Оцените материал
Добавить комментарий

Капча загружается...