我正在尝试对文本文件进行排序,其中的行采用以下格式:
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 6
并希望按数字顺序排序,以最后的数字(即本例中为6)进行排序。这些行没有可预测数量的列,使用空格作为分隔符,但使用|||作为分隔符,总是有5列,最后一列总是有3个空格分隔的数字,最后一个要排序。文本文件大约是15gb,我确实有一个perl脚本,我写了这样做,但它只适用于我的旧笔记本电脑有32GB的RAM,因为perl一次加载整个文件。现在我卡住了8GB内存,它只是在几天内交换文件。我听说标准的linux sort命令可以更优雅地处理大文件,但我找不到一种方法可以让它最后使用这个数字。
答案 0 :(得分:4)
也许这有点棘手,但这种混合命令可以实现:
awk '$1=$NF" "$1' file | sort -n | cut -d' ' -f2-
主要的想法是我们打印在行前面附加最后一个值的文件,然后我们排序,最后我们从输出中删除该值。
awk '$1=$NF" "$1' file
由于您要排序的参数是文件中的最后一个,我们也会在第一个字段中打印它。sort -n
然后我们输入sort -n
,按数字排序。cut -d' ' -f2-
我们最终打印出我们暂时使用的值。$ cat a
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 6
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 79
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 19
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 8
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 89
$ awk '$1=$NF" "$1' a | sort -n | cut -d' ' -f2-
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 6
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 8
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 19
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 79
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 89
显示每个步骤:
$ awk '$1=$NF" "$1' a
6 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 6
79 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 79
19 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 19
8 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 8
89 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 89
$ awk '$1=$NF" "$1' a | sort -n
6 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 6
8 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 8
19 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 19
79 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 79
89 ! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 89
$ awk '$1=$NF" "$1' a | sort -n | cut -d' ' -f2-
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 6
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 8
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 19
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 79
! ! ! ! ! ||| ! ||| 1.25846e-05 0.248369 3.02708e-07 0.662955 2.718 ||| 0-0 1-0 2-0 3-0 4-0 ||| 476773 1.98211e+07 89
答案 1 :(得分:1)
您似乎想根据最后一个号码订购文件,对吗?
因此,您可以使用awk
复制该行开头的最后一个字段awk -F, '{ print $NF, $0 }' prova
然后用
对文件进行排序sort -n -k1
最后删除假的第一个字段:
sed 's/^[0-9][0-9]* //'
这是脚本:
awk -F, '{ print $NF, $0 }' prova | sort -n -k1 | sed 's/^[0-9][0-9]* //'
答案 2 :(得分:0)
由于问题是RAM,也许你可以减少使用Tie::File
所需的内存。它允许您通过数组中的索引引用一行。您可以获取要排序的数字并使用Schwartzian transform获取排序的索引列表,然后在最后重新打印该文件。
use strict;
use warnings;
use Tie::File;
my $file = shift; # your filename argument
tie my @lines, 'Tie::File', $file or die $!;
my @list = map $_->[0], # restore line number
sort { $b->[1] <=> $a->[1] } # sort on captured number
map { [ $_, $lines[$_] =~ /(\d+)$/ ] } 0 .. $#lines;
# store an array ref [ ... ] containing line number and number to
# sort by
@lines = @lines[@list];
最后一个操作将按排序顺序保存文件。请注意,这是永久性更改,因此请进行备份。这可能也是一项昂贵的操作,Tie::File
有一些性能问题。另一种方法,可能更便宜的是简单地遍历数字列表并逐行打印到新文件:
open my $fh, ">", "output.csv" or die $!;
for my $num (@list) {
print $fh $lines[$num], $/;
}
直接打印到文件会绕过重定向输出所需的任何shell缓存
答案 3 :(得分:0)
假设我允许破坏原始文件(否则复制),您可以通过滚动文件一次并将最后一列转换为可预测的列号,对最后一列使用sort。我使用@
符号作为我认为不会出现在您数据中的符号。如果这是一个不好的假设,任何事情都可以替代。
sed -i 's/ /@/g; s/@\([^@]*\)$/ \1/;' in.txt
# the file now looks like "!@!@|||@whatever@||| 6"
sort --buffer-size=1G -nk 2 in.txt | sed 's/@/ /g' > sorted.txt