Büyük bir metin dosyası eşit sayıda satıra sahip daha küçük dosyalara nasıl bölünür?


515

Daha küçük dosyalara, ayrıca satır sayısına bölmek istediğim büyük (satır sayısına göre) düz metin dosyası var. Dosyamın yaklaşık 2M satırı varsa, 200k satır içeren 10 dosyaya veya 20k satır içeren 100 dosyaya (artı kalan bir dosya; eşit olarak bölünebilir olması önemli değildir) bölmek istiyorum.

Bunu Python'da oldukça kolay yapabilirdim, ancak bash ve unix araçlarını kullanarak (elle döngü ve sayma / bölme çizgilerinin aksine) bunu yapmak için herhangi bir ninja yolu olup olmadığını merak ediyorum.


2
Merakla, "ayrıldıktan" sonra, onları nasıl "birleştirir"? "Cat part2 >> part1" gibi bir şey mi? Yoksa başka bir ninja yardımcı programı var mı? sorunuzu güncellemek ister misiniz?
dlamotte

7
Bir araya getirmek için,cat part* > original
Mark Byers

9
evet kedi bitiştirmek için kısadır. Genel olarak uygun olan uygun komutları bulmak için kullanışlıdır. IE çıktı görmek: apropos split
pixelbeat

@pixelbeat Çok güzel, teşekkürler
danben

3
Bir kenara, OS X kullanıcıları dosyalarının MAC OS X - stil sonu çizgi göstergeleri (CR) yerine bölünmüş ve Benzer sonlarınız LineFeeds yerine Satır Başı ise csplit komutları çalışmaz. BareBones yazılımından TextWrangler, Mac OS kullanıyorsanız bu konuda size yardımcı olabilir. Satır sonu karakterlerinizin nasıl görünmesini istediğinizi seçebilirsiniz. metin dosyalarınızı kaydettiğinizde (veya Farklı Kaydet ...).

Yanıtlar:


856

Split komutuna baktınız mı?

$ 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

Bunun gibi bir şey yapabilirsiniz:

split -l 200000 filename

her biri 200000 satırında xaa xab xac...

Çıkış dosyasının boyutuna göre bölünmüş başka bir seçenek (yine de satır sonlarına bölünüyor):

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

output_prefix01 output_prefix02 output_prefix03 ...her biri maksimum 20 megabayt boyutunda dosyalar oluşturur .


16
ayrıca bir dosyayı boyuta göre bölebilirsiniz: split -b 200m filename(megabayt için m, kilobayt için k veya bayt için sonek yok)
Abhi Beckert

136
boyuta göre bölün ve dosyaların satır sonlarında bölünmesini sağlayın: bölünmüş -C 200m dosya adı
Clayton Stanley

2
split, Unicode (UTF-16) girişi ile bozuk çıktı üretir. En azından Windows sürümüm var.
Vertigo

4
@geotheory, TextWrangler veya BBEdit kullanarak CR (Mac) satır sonlarını LR (Linux) satır sonlarına dönüştürme konusunda LeberMac'ın başlığında daha önce yer alan tavsiyelere uyduğunuzdan emin olun. Bu tavsiyeyi bulana kadar seninle aynı problemi yaşadım.
sstringer

6
-dseçeneği OSX'te kullanılamaz, gsplitbunun yerine kullanın. Bu Mac kullanıcı için yararlı umuyoruz.
user5698801


39

Evet, bir splitkomut var. Bir dosyayı satırlara veya baytlara böler.

$ 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.

Denenmiş georgec @ ATGIS25 ~ $ split -l 100000 /cygdrive/P/2012/Job_044_DM_Radio_Propogation/Working/FinalPropogation/TRC_Longlands/trc_longlands.txt ama dizinde bölünmüş dosya yok - çıktı nerede?
GeorgeC

1
Aynı dizinde olmalıdır. Örneğin ben, dosya başına 1.000.000 çizgilerle bölünmüş istediğiniz aşağıdakileri yaparsanız: split -l 1000000 train_file train_file.ve aynı dizinde ben alırsınız train_file.aasonra, ilk milyon ile trail_file.abvb sonraki milyonda ile
Will

1
@GeorgeC ve: önekiyle özel çıktı dizinleri alabilirsiniz split input my/dir/.
Ciro Santilli 法轮功 冠状 病 六四 事件 法轮功

15

kullanım split

Bir dosyayı sabit boyutlu parçalara böler, art arda INPUT bölümlerini içeren çıktı dosyaları oluşturur (hiçbiri verilmemişse veya INPUT `- 'ise standart girdi)

Syntax split [options] [INPUT [PREFIX]]

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


13

kullanın:

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

Burada 1 ve 100, yakalayacağınız satır numaralarıdır output.txt.


Bu sadece ilk 100 satırı alır, dosyayı bir sonraki 101..200 vb.'ye art arda bölmek için döngüye almanız gerekir. Ya da sadece splitburada en iyi yanıtların size söylediği gibi kullanın .
tripleee

10

"file.txt" dosyasını 10000 satır dosyaya bölme:

split -l 10000 file.txt

9

split(GNU coreutils'ten, 2010-12-22 sürüm 8.8'den bu yana ) aşağıdaki parametreyi içerir:

-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

Böylece, aynı miktarda bayt ile split -n 4 input output.dört dosya ( output.a{a,b,c,d}) oluşturur , ancak satırlar ortada kırılmış olabilir.

Tam satırları (yani satırlara bölünmüş) korumak istiyorsak, bu işe yaramalıdır:

split -n l/4 input output.

İlgili cevap: https://stackoverflow.com/a/19031247


9

Her dosyada yalnızca x satır sayısına bölmek istediğinizde, verilen cevaplar splitdoğru olacaktır. Ancak, hiç kimsenin gereksinimlere dikkat etmediğini merak ediyorum:

  • "saymak zorunda kalmadan" -> wc + cut kullanarak
  • "Kalan dosyanın fazladan dosyada bulunması" -> split varsayılan olarak

Bunu "wc + cut" olmadan yapamam, ama kullanıyorum:

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

Bu, bashrc işlevlerinize kolayca eklenebilir, böylece sadece dosya adını ve parçalarını geçerek çalıştırabilirsiniz:

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

Ekstra dosyada sadece x parçası kalmasını istemiyorsanız, formülü her dosyada (parçalar - 1) toplamak için uyarlamanız yeterlidir. Ben genellikle sadece x dosya başına x satır yerine dosya sayısı x istiyorum çünkü bu yaklaşımı kullanın:

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

Bunu bir senaryoya ekleyebilir ve "ninja yolu" olarak adlandırabilirsiniz, çünkü hiçbir şey ihtiyaçlarınızı karşılamıyorsa, onu oluşturabilirsiniz :-)


Veya, sadece -nseçeneğini kullanın split.
Amit Naidu

8

awk da kullanabilirsiniz

awk -vc=1 'NR%200000==0{++c}{print $0 > c".txt"}' largefile

3
awk -v lines=200000 -v fmt="%d.txt" '{print>sprintf(fmt,1+int((NR-1)/lines))}'
Mark Edgar

0

HDFS getmerge küçük dosya ve özellik boyutuna döküldü.

Bu yöntem satır kesmesine neden olur

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

Getmerge ve her dosyada yaklaşık 128MB'a bölünmeye çalışıyorum.

# 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}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.