我熟悉linux中的split命令。 如果我有一个100行的文件,
split -l 5 myfile.txt
…将myfile.txt分成20个文件,每个文件有5行,并将它们写入文件。
我的问题是,我想按栏来做。 给定一个文件有100列,制表符分隔,是否有一个类似的命令将这个文件分成20个小文件,每个文件有5列和所有的行?
我知道如何使用剪切,但我希望有一个简单的UNIX命令,我从来没有听说过,这将完成这个没有包装削减与Perl或东西。
提前致谢。
#!/bin/bash (($# == 2)) || { echo -e "\nUsage: $0 <file to split> <# columns in each split>\n\n"; exit; } infile="$1" inc=$2 ncol=$(awk 'NR==1{print NF}' "$infile") ((inc < ncol)) || { echo -e "\nSplit size >= number of columns\n\n"; exit; } for((i=0, start=1, end=$inc; i < ncol/inc + 1; i++, start+=inc, end+=inc)); do cut -f$start-$end "$infile" > "${infile}.$i" done
谢谢您的帮助。 我希望有一个类似于split的unix命令,但是我最终通过SiegeX的建议用perl封装了这个命令。
#!/usr/bin/perl chomp(my $pwd = `pwd`); my $help = "\nUsage: $0 <file to split> <# columns in each split>\n\n"; die $help if @ARGV!=2; $infile = $ARGV[0]; chomp($ncol = `head -n 1 $infile | wc -w`); $start=1; $inc = $ARGV[1]; $end = $start+$inc-1; die "\nSplit size >= number of columns\n\n" if $inc>=$ncol; for($i=1 ; $i<$ncol/$inc +1 ; $i++) { if ($end>$ncol) {$end=$ncol;} `cut -f $start-$end $infile > $infile.$i`; $start += $inc; $end += $inc; }
如果你只需要一个QAD(快速和肮脏)的解决方案在我的情况下一个固定的8列; 分开csv
#!/bin/bash # delimiter is ; cut -d';' -f1 "$1" > "${1}.1" cut -d';' -f2 "$1" > "${1}.2" cut -d';' -f3 "$1" > "${1}.3" cut -d';' -f4 "$1" > "${1}.4" cut -d';' -f5 "$1" > "${1}.5" cut -d';' -f6 "$1" > "${1}.6" cut -d';' -f7 "$1" > "${1}.7" cut -d';' -f8 "$1" > "${1}.8"
# do something smarter with output files (& clear on start) XIFS="${IFS}" IFS=$'\t' while read -a LINE; do for (( i=0; i< ${#LINE[@]}; i++ )); do echo "${LINE[$i]}" >> /tmp/outfile${i} done done < infile IFS="${XIFS}"
尝试以上…使用文件名'infile'
注意保存和恢复IFS(有没有人有更好的主意?一个子shell?)
另外请注意,如果您正在运行第二次,则会追加 – 您想要删除之前运行的输出…
在这里你有我的解决方案:
首先是输入发生器:
1 #!/usr/bin/env ruby 2 # 3 def usage(e) 4 puts "Usage #{__FILE__} <n_rows> <n_cols>" 5 exit e 6 end 7 8 usage 1 unless ARGV.size == 2 9 10 rows, cols = ARGV.map{|e| e.to_i} 11 (1..rows).each do |l| 12 (1..cols).each {|c| printf "%s ", c } 13 puts "" 14 end
拆分工具:
1 #!/usr/bin/env ruby 2 # 3 4 def usage(e) 5 puts "Usage #{__FILE__} <column_start> <column_end>" 6 exit e 7 end 8 9 usage 1 unless ARGV.size == 2 10 11 c_start, c_end = ARGV.map{|e| e.to_i} 12 i = 0 13 buffer = [] 14 $stdin.each_line do |l| 15 i += 1 16 buffer << l.split[c_start..c_end].join(" ") 17 $stderr.printf "\r%d", i if i % 100000 == 0 18 end 19 $stderr.puts "" 20 buffer.each {|l| puts l}
请注意,拆分工具会将stderr转储到正在处理的行数中,以便您了解速度有多快。
另外,我假设分隔符是一个空格。
如何运行它的例子:
$ time ./gen.data.rb 1000 10 | ./split.rb 0 4 > ./out
生成1000行,每行10列,分割前5列。 我用时间(1)来衡量运行时间。
我们可以使用一个小字体来做你要求的分割(依次)。 在单个节点中并行处理它非常简单(检查bash构建命令等待)或将它们发送到集群。
$ ruby -e '(0..103).each {|i| puts "cat input.txt | ./split.rb #{i-4} #{i} > out.#{i/4}" if i % 4 == 0 && i > 0}' | /bin/bash
基本上生成:
cat input.txt | ./split.rb 0 4 > out.1 cat input.txt | ./split.rb 4 8 > out.2 cat input.txt | ./split.rb 8 12 > out.3 cat input.txt | ./split.rb 12 16 > out.4 cat input.txt | ./split.rb 16 20 > out.5 cat input.txt | ./split.rb 20 24 > out.6 cat input.txt | ./split.rb 24 28 > out.7 cat input.txt | ./split.rb 28 32 > out.8 cat input.txt | ./split.rb 32 36 > out.9 cat input.txt | ./split.rb 36 40 > out.10 cat input.txt | ./split.rb 40 44 > out.11 cat input.txt | ./split.rb 44 48 > out.12 cat input.txt | ./split.rb 48 52 > out.13 cat input.txt | ./split.rb 52 56 > out.14 cat input.txt | ./split.rb 56 60 > out.15 cat input.txt | ./split.rb 60 64 > out.16 cat input.txt | ./split.rb 64 68 > out.17 cat input.txt | ./split.rb 68 72 > out.18 cat input.txt | ./split.rb 72 76 > out.19 cat input.txt | ./split.rb 76 80 > out.20 cat input.txt | ./split.rb 80 84 > out.21 cat input.txt | ./split.rb 84 88 > out.22 cat input.txt | ./split.rb 88 92 > out.23 cat input.txt | ./split.rb 92 96 > out.24 cat input.txt | ./split.rb 96 100 > out.25
并得到管道抨击。
请注意并行计算的进程(或作业)的数量,因为这会浪费存储空间(除非有独立的存储卷)。
希望有所帮助。 让我们知道它有多快为您运行。
-drd
斯普利特实际上可以做你想做的事情,做一点预处理
sed -E $'s/(([^\t]+\t){4}[^\t]+)\t/\\1\\n/g' myfile.txt | split -nr/20
这将写出20个文件的x
前缀(在我的版本的拆分)。 你可以验证这个工作:
paste x* | cmp - myfile.txt
基本上这是用sed
把每一行分成二十行,然后用循环块来分割每一行到合适的文件。 要使用不同的分隔符,请切换表达式中的选项卡。 数字4应该是每个文件的列数 – 1,并且在结尾处的20是文件的数量。 可以使用其他的分割参数来修改写入的文件名。 这个例子使用bashes escape expansion将选项卡写入sed表达式和一个可以使用+
运算符的sed版本,但是如果系统中不存在这些效果,可以通过替代方法实现。
我从coreutils邮件列表中找到了来自Reuti的这个解决方案的一个变体。