Как разбить большой текстовый файл на более мелкие файлы с одинаковым количеством строк?

517

У меня есть большой (по количеству строк) простой текстовый файл, который я хотел бы разбить на более мелкие файлы, в том числе по количеству строк. Таким образом, если мой файл имеет около 2M строк, я бы хотел разделить его на 10 файлов, содержащих 200k строк, или 100 файлов, содержащих 20k строк (плюс один файл с остатком; быть равномерно делимым не имеет значения).

Я мог бы сделать это довольно легко в Python, но мне интересно, есть ли какой-нибудь способ ниндзя сделать это, используя утилиты bash и unix (в отличие от ручного зацикливания и подсчета / разбиения строк).

danben
источник
2
Из любопытства, после того, как они «разделены», как их «объединить»? Что-то вроде "кошка часть2 >> часть1"? Или есть еще одна утилита ниндзя? возражаете обновить свой вопрос?
dlamotte
7
Чтобы собрать это вместе,cat part* > original
Марк Байерс
9
да, кошка коротка для конкатенации. В целом, урок полезен для поиска соответствующих команд. IE видит вывод:
apropos
@pixelbeat Это очень круто, спасибо
Данбен
3
Кроме того, пользователи OS X должны убедиться, что их файл содержит разрывы строк / индикаторы конца строки (LF) в стиле LINUX или UNIX вместо MAC OS X - индикаторы конца строки (CR) в стиле - разделение и Команды csplit не будут работать, если ваши подобные разрывы - это возврат каретки вместо LineFeeds. TextWrangler от BareBones поможет вам в этом, если вы работаете в Mac OS. Вы можете выбрать, как вы хотите, чтобы ваши символы разрыва строки выглядели. когда вы сохраняете (или сохраняете как ...) ваши текстовые файлы.

Ответы:

858

Вы смотрели на команду split?

$ split --help
Usage: split [OPTION] [INPUT [PREFIX]]
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default
size is 1000 lines, and default PREFIX is `x'.  With no INPUT, or when INPUT
is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -a, --suffix-length=N   use suffixes of length N (default 2)
  -b, --bytes=SIZE        put SIZE bytes per output file
  -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file
  -d, --numeric-suffixes  use numeric suffixes instead of alphabetic
  -l, --lines=NUMBER      put NUMBER lines per output file
      --verbose           print a diagnostic to standard error just
                            before each output file is opened
      --help     display this help and exit
      --version  output version information and exit

Вы могли бы сделать что-то вроде этого:

split -l 200000 filename

который создаст файлы каждый с 200000 строк с именем xaa xab xac...

Другой вариант, разделенный по размеру выходного файла (по-прежнему разбивается на разрывы строк):

 split -C 20m --numeric-suffixes input_filename output_prefix

создает файлы output_prefix01 output_prefix02 output_prefix03 ...размером не более 20 мегабайт.

Марк Байерс
источник
16
Вы также можете разделить файл по размеру: split -b 200m filename(м для мегабайт, к для килобайт или без суффикса для байтов)
Абхи Бекерт
137
разделить по размеру и убедиться, что файлы разбиты на разрывы строк: разделить -C 200m имя файла
Clayton Stanley
2
split дает искаженный вывод с помощью ввода Unicode (UTF-16). По крайней мере, на Windows с версией, которую я имею.
Головокружение
4
@geotheory, обязательно следуйте совету LeberMac ранее в теме о первом преобразовании концов строк CR (Mac) в окончания строк LR (Linux) с использованием TextWrangler или BBEdit. У меня была та же проблема, что и у вас, пока я не нашел этот совет.
sstringer
6
-dопция недоступна в OSX, используйте gsplitвместо этого. Надеюсь, что это полезно для пользователей Mac.
user5698801
80

Как насчет команды split ?

split -l 200000 mybigfile.txt
Роберт Кристи
источник
39

Да, есть splitкоманда. Он разделит файл на строки или байты.

$ split --help
Usage: split [OPTION]... [INPUT [PREFIX]]
Output fixed-size pieces of INPUT to PREFIXaa, PREFIXab, ...; default
size is 1000 lines, and default PREFIX is `x'.  With no INPUT, or when INPUT
is -, read standard input.

Mandatory arguments to long options are mandatory for short options too.
  -a, --suffix-length=N   use suffixes of length N (default 2)
  -b, --bytes=SIZE        put SIZE bytes per output file
  -C, --line-bytes=SIZE   put at most SIZE bytes of lines per output file
  -d, --numeric-suffixes  use numeric suffixes instead of alphabetic
  -l, --lines=NUMBER      put NUMBER lines per output file
      --verbose           print a diagnostic just before each
                            output file is opened
      --help     display this help and exit
      --version  output version information and exit

SIZE may have a multiplier suffix:
b 512, kB 1000, K 1024, MB 1000*1000, M 1024*1024,
GB 1000*1000*1000, G 1024*1024*1024, and so on for T, P, E, Z, Y.
Дейв Кирби
источник
Пробовал georgec @ ATGIS25 ~ $ split -l 100000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt, но в каталоге нет разделенных файлов - где вывод?
GeorgeC
1
Это должно быть в том же каталоге. Например , если я хочу разделить на 1000000 строк в файл, выполните следующие действия : split -l 1000000 train_file train_file.и в том же каталоге , я буду получать train_file.aaс первым миллионом, то trail_file.abсо следующим миллионом, и т.д.
Будет
1
@GeorgeC и вы можете получить пользовательские выходные каталоги с префиксом: split input my/dir/.
Сиро Сантилли 郝海东 冠状 病 六四 事件 法轮功
15

использование split

Разбивает файл на части фиксированного размера, создает выходные файлы, содержащие последовательные разделы INPUT (стандартный ввод, если ничего не задано или INPUT равен `- ')

Syntax split [options] [INPUT [PREFIX]]

http://ss64.com/bash/split.html

zmbush
источник
13

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

sed -n '1,100p' filename > output.txt

Здесь 1 и 100 - номера строк, которые вы будете записывать output.txt.

Harshwardhan
источник
При этом получаются только первые 100 строк, вам нужно зациклить его, чтобы последовательно разбить файл на следующие 101..200 и т. Д. Или просто использовать, splitкак уже говорилось во всех верхних ответах.
tripleee
10

разбить файл "file.txt" на 10000 строк файлов:

split -l 10000 file.txt
ialqwaiz
источник
9

split(из GNU coreutils, начиная с версии 8.8 от 2010-12-22 ) включает в себя следующий параметр:

-n, --number=CHUNKS     generate CHUNKS output files; see explanation below

CHUNKS may be:
  N       split into N files based on size of input
  K/N     output Kth of N to stdout
  l/N     split into N files without splitting lines/records
  l/K/N   output Kth of N to stdout without splitting lines/records
  r/N     like 'l' but use round robin distribution
  r/K/N   likewise but only output Kth of N to stdout

Таким образом, split -n 4 input output.сгенерирует четыре файла (output.a{a,b,c,d} ) с одинаковым количеством байтов, но строки могут быть разбиты посередине.

Если мы хотим сохранить полные строки (т.е. разделенные на строки), то это должно работать:

split -n l/4 input output.

Соответствующий ответ: https://stackoverflow.com/a/19031247

Денилсон Са Майя
источник
9

В случае, если вы просто хотите разделить на x количество строк в каждом файле, данные ответы splitв порядке. Но мне интересно, чтобы никто не обращал внимания на требования:

  • "не считая их" -> используя wc + cut
  • "имея остаток в дополнительном файле" -> по умолчанию делает split

Я не могу сделать это без "wc + cut", но я использую это:

split -l  $(expr `wc $filename | cut -d ' ' -f3` / $chunks) $filename

Это может быть легко добавлено к вашим функциям bashrc, так что вы можете просто вызывать его, передавая имя файла и чанки:

 split -l  $(expr `wc $1 | cut -d ' ' -f3` / $2) $1

Если вам нужно только x кусков без остатка в дополнительном файле, просто измените формулу, чтобы суммировать ее (куски - 1) в каждом файле. Я использую этот подход, потому что обычно я просто хочу x количество файлов, а не x строк на файл:

split -l  $(expr `wc $1 | cut -d ' ' -f3` / $2 + `expr $2 - 1`) $1

Вы можете добавить это в скрипт и назвать его «ниндзя-путь», потому что, если ничего не соответствует вашим потребностям, вы можете создать его :-)

m3nda
источник
Или просто используйте -nопцию split.
Амит Найду
8

Вы также можете использовать awk

awk -vc=1 'NR%200000==0{++c}{print $0 > c".txt"}' largefile
ghostdog74
источник
3
awk -v lines=200000 -v fmt="%d.txt" '{print>sprintf(fmt,1+int((NR-1)/lines))}'
Марк Эдгар
0

HDFS getmerge небольшой файл и вылил в размер свойства.

Этот метод вызовет разрыв строки

split -b 125m compact.file -d -a 3 compact_prefix

Я пытаюсь объединить и разделить на 128 МБ каждый файл.

# split into 128m ,judge sizeunit is M or G ,please test before use.

begainsize=`hdfs dfs -du -s -h /externaldata/$table_name/$date/ | awk '{ print $1}' `
sizeunit=`hdfs dfs -du -s -h /externaldata/$table_name/$date/ | awk '{ print $2}' `
if [ $sizeunit = "G" ];then
    res=$(printf "%.f" `echo "scale=5;$begainsize*8 "|bc`)
else
    res=$(printf "%.f" `echo "scale=5;$begainsize/128 "|bc`)  # celling ref http://blog.csdn.net/naiveloafer/article/details/8783518
fi
echo $res
# split into $res files with number suffix.  ref  http://blog.csdn.net/microzone/article/details/52839598
compact_file_name=$compact_file"_"
echo "compact_file_name :"$compact_file_name
split -n l/$res $basedir/$compact_file -d -a 3 $basedir/${compact_file_name}
Matiji66
источник