Подтвердить что ты не робот

Как разбить большой файл на множество небольших файлов с помощью 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 строки).

Есть ли лучший способ сделать это?

4b9b3361

Ответ 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 на самом деле наиболее часто используется для распараллеливания конвейеров. ИМХО - инструмент, который стоит изучить.