Как разбить большой файл на множество небольших файлов с помощью bash?
У меня есть файл, скажем all
, с 2000 строк, и я надеюсь, что его можно разделить на 4 небольших файла с номером строки 1 ~ 500, 501 ~ 1000, 1001 ~ 1500, 1501 ~ 2000.
Возможно, я могу сделать это, используя:
cat all | head -500 >small1
cat all | tail -1500 | head -500 >small2
cat all | tail -1000 | head -500 >small3
cat all | tail -500 >small4
Но этот способ включает вычисление номера строки, что может вызвать ошибку, когда количество строк не является хорошим числом или когда мы хотим разбить файл на слишком много небольших файлов (например: файл all
с 3241 линии, и мы хотим разбить его на 7 файлов, каждая из которых имеет 463 строки).
Есть ли лучший способ сделать это?
Ответы
Ответ 1
Если вы хотите разбить файл, используйте split
:
split -l 500 all all
разделит файл на несколько файлов, каждая из которых имеет 500 строк. Если вы хотите разбить файл на 4 файла примерно того же размера, используйте что-то вроде:
split -l $(( $( wc -l < all ) / 4 + 1 )) all all
Ответ 2
Посмотрите на команду 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 generate suffixes of length N (default 2)
--additional-suffix=SUFFIX append an additional SUFFIX to file names.
-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[=FROM] use numeric suffixes instead of alphabetic.
FROM changes the start value (default 0).
-e, --elide-empty-files do not generate empty output files with '-n'
--filter=COMMAND write to shell COMMAND; file name is $FILE
-l, --lines=NUMBER put NUMBER lines per output file
-n, --number=CHUNKS generate CHUNKS output files. See below
-u, --unbuffered immediately copy input to output with '-n r/...'
--verbose print a diagnostic just before each
output file is opened
--help display this help and exit
--version output version information and exit
SIZE is an integer and optional unit (example: 10M is 10*1024*1024). Units
are K, M, G, T, P, E, Z, Y (powers of 1024) or KB, MB, ... (powers of 1000).
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
l/K/N output Kth of N to stdout without splitting lines
r/N like 'l' but use round robin distribution
r/K/N likewise but only output Kth of N to stdout
Ответ 3
Как уже упоминалось выше, вы можете использовать split
. Сложная подстановка команд, о которой говорится в принятом ответе, не требуется. Для справки я добавляю следующие команды, которые выполняют почти то, что было запросом. Обратите внимание, что при использовании аргумента командной строки -n
для указания количества патронов файлы small*
не содержат ровно 500 строк при использовании split
.
$ seq 2000 > all
$ split -n l/4 --numeric-suffixes=1 --suffix-length=1 all small
$ wc -l small*
583 small1
528 small2
445 small3
444 small4
2000 total
В качестве альтернативы вы можете использовать GNU parallel:
$ < all parallel -N500 --pipe --cat cp {} small{#}
$ wc -l small*
500 small1
500 small2
500 small3
500 small4
2000 total
Как вы можете видеть, это заклинание довольно сложно. GNU Parallel на самом деле наиболее часто используется для распараллеливания конвейеров. ИМХО - инструмент, который стоит изучить.