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