我想要一个相对紧凑的命令来执行文本文件的逐行去交错,即
a1
a2
a3
a4
b1
b2
b3
b4
c1
c2
c3
c4
d1
d2
d3
d4
映射到
a1
b1
c1
d1
a2
b2
c2
d2
a3
b3
c3
d3
a4
b4
c4
d4
交织深度应该是可调的。这些行本身不包含任何有用的结构来帮助该过程,上面的示例只是一个用于演示目的的玩具示例。我可以使用什么工具来做到这一点?
基本上,您正在做的是将数据读入二维数组。当您读入它时,您可以(例如)将数据逐行放入数组中。
然后当你写出数据时,你逐列遍历数组。调整您所做的(去)交错只需要不同大小的数组(或者至少您使用不同数量的数组,尽管如果您选择,您可以将数组大小本身固定)。
sort
可以做到!
$ sort -k1.2 your_file
-k1.2
从第二个字符开始按第一个字段排序。
输出:
a1
b1
c1
d1
a2
b2
c2
d2
a3
b3
c3
d3
a4
b4
c4
d4
更新
终于明白了你的问题,感谢TLP
,我建议这个解决方案。它需要命令行上的深度和输入文件名:
$ perl deinter.pl 4 interleaved.txt
并将重新排序的数据打印到 STDOUT。
use strict;
use warnings;
my $depth = shift;
my @data = <>;
for my $start (0 .. $depth-1) {
for (my $i = $start; $i < @data; $i += $depth) {
print $data[$i];
}
}
输出
a1
b1
c1
d1
a2
b2
c2
d2
a3
b3
c3
d3
a4
b4
c4
d4
以前的解决方案
这是一种将整个文件读入内存的技术,构建一组用于比较的键,并对数据的索引进行排序,以便它们可以以新的顺序打印。
通过修改提取键字段的正则表达式并更改排序块以使排序顺序正确,可以根据您的目的对其进行更改。
如果您的文件很大,那么可能只需要在内存中构建键数组,并将文件中的其余数据保留为在输出时读取。
use strict;
use warnings;
open my $fh, '<', 'interleaved.txt' or die $!;
my @data = <$fh>;
my @keys = map [ /^(.)(.)/ ], @data;
my @sorted = sort {
$keys[$a][1] <=> $keys[$b][1] or
$keys[$a][0] cmp $keys[$b][0]
} 0 .. $#keys;
print $data[$_] for @sorted;
根据您的新要求,根据元素在文件中的位置重新排序元素:
use strict;
use warnings;
my @sorted;
my $depth = 4; # the adjustable interleaving depth
while (<DATA>) {
my $num = ($. % $depth) - 1; # $. is input line number
push @{ $sorted[$num] }, $_;
}
for (@sorted) {
print @$_;
}
__DATA__
a1
a2
a3
a4
b1
b2
b3
b4
c1
c2
c3
c4
d1
d2
d3
d4
<DATA>
请注意,可以通过更改为<>
并运行以下命令在输入文件上测试脚本:
perl script.pl input.txt
这可能对您有用(GNU sed 和排序):
sed '1{x;s/^/1/;x};G;s/\n/\t/p;x;y/1234/2341/;x;d' file|sort -sk2|sed 's/\t.*//'
我想感谢他们的投入和回答,这激发了解决方案Borodin
。TLP
好丑,不过我喜欢
awk 'BEGIN{v=4}{now=(NR-1)%v; STOR[now] = STOR[now] "\n" $0;} END {for (v in STOR) print STOR[v]}'
它还具有打印虚假换行符的缺陷(嗯,附加到数组开头的换行符),但我可以处理。
编辑:
换行符的解决方案:
awk 'BEGIN{v=4}{now=(NR-1)%v; STOR[now] = STOR[now] "\n" $0;} END {for (v in STOR) print substr(STOR[v],2)}'