我有一个名单清单,这些清单不正常。如何使用字母部分的自定义排序顺序以正确的字母数字顺序获取它们?
我的档案numbers.txt
:
alpha-1
beta-3
alpha-10
beta-5
alpha-5
beta-1
gamma-7
gamma-1
delta-10
delta-2
重点是我的脚本应该识别它应该在alpha
之前打印beta
,在beta
之前打印gamma
,在{{之前打gamma
1}}。
也就是说,这些单词应该根据它们所代表的希腊字母中字母的顺序进行排序。
预期订单:
delta
PS:我尝试使用alpha-1
alpha-5
alpha-10
beta-1
beta-3
beta-5
gamma-1
gamma-7
delta-2
delta-10
,但这不符合我的需要。
答案 0 :(得分:2)
您可以使用辅助awk
命令,如下所示:
awk -F- -v keysInOrder="alpha,beta,gamma,delta" '
BEGIN {
split(keysInOrder, a, ",")
for (i = 1; i <= length(a); ++i) keysToOrdinal[a[i]] = i
}
{ print keysToOrdinal[$1] "-" $0 }
' numbers.txt | sort -t- -k1,1n -k3,3n | cut -d- -f2-
awk
命令用于:
将自定义键映射到反映所需排序顺序的数字;请注意,完整的键列表必须按顺序通过变量keysInOrder
传递。
使用分隔符-
将数字作为辅助列添加到输入中;例如,beta-3
变为2-beta-3
,因为beta
在排序键的有序列表中位于 2 位置。
sort
然后按映射的数字以及第二列中的原始数字对awk
的输出进行排序,从而产生所需的自定义排序顺序。
cut
然后移除辅助。再次映射数字。
答案 1 :(得分:1)
我会在这里找到Perl。这个脚本可以工作:
#!/usr/bin/env perl
use v5.14; # turn on modern features
# Greek alphabet
my @greek_letters =qw(alpha beta gamma delta epsilon zeta
eta theta iota kappa lambda mu
nu xi omicron pi rho sigma
tau upsilon phi chi psi omega);
# An inverted map from letter name to position number;
# $number{alpha} = 1, $number{beta} = 2, etc:
my %number;
@number{@greek_letters} = 1..@greek_letters;
# Read the lines to sort
chomp(my @lines = <>);
# split on hyphen into arrays of individual fields
my @rows = map { [ split /-/ ] } @lines;
# prepend the numeric position of each item's Greek letter
my @keyed = map { [ $number{$_->[0]}, @$_ ] } @rows;
# sort by Greek letter position (first field, index 0) and then
# by final number (third field, index 2)
my @sorted = sort { $a->[0] <=> $b->[0]
|| $a->[2] <=> $b->[2] } @keyed;
# remove the extra field we added
splice(@$_, 0, 1) for @sorted;
# combine the fields back into strings and print them out
say join('-', @$_) for @sorted;
将Perl代码保存到文件中(例如greeksort.pl
)并运行perl greeksort.pl numbers.txt
以获取已排序的输出。
答案 2 :(得分:1)
这是一个Python解决方案。不要尝试用Bash,sed,awk做一些艰难的事情。你通常可以完成你想要的,但它会更容易混淆,更容易出错,而且难以维护。
--skip-compilation
答案 3 :(得分:0)
通用解决方案: sort -t- -k 1,1 -k 2,2n numbers.txt
以下脚本适用于自定义要求。这不是最好的解决方案。 结果将再次存储在numbers.txt
中#!/bin/bash
sort -t- -k 1,1 -k 2,2n numbers.txt > new_test.txt
while IFS= read -r i
do
if [[ $i == *"delta"* ]]
then
echo $i >> temp_file
else
echo $i >> new_numbers.txt
fi
done < new_test.txt
cat temp_file >> new_numbers.txt
cat new_numbers.txt > numbers.txt
rm -rf new_test.txt
rm -rf temp_file
rm -rf new_numbers.txt
答案 4 :(得分:0)
如果您有权访问awk和sed,请尝试使用
为希腊语订购添加更改..
cat test.txt | awk -F "-" '{ printf "%s-%0100i\n" , $1, $2 }' | \ sed 's/^alpha-\(.*\)$/01-\1/' | \ sed 's/^beta-\(.*\)$/02-\1/' | \ sed 's/^gamma-\(.*\)$/03-\1/' | \ sed 's/^delta-\(.*\)$/04-\1/' | \ sort | \ sed 's/\(.*\)-\([0]*\)\(.*\)/\1-\3/' | \ sed 's/^01-\(.*\)$/alpha-\1/' | \ sed 's/^02-\(.*\)$/beta-\1/' | \ sed 's/^03-\(.*\)$/gamma-\1/' | \ sed 's/^04-\(.*\)$/delta-\1/'
答案 5 :(得分:0)
不要试图用Bash,sed,awk做硬事
是的,使用实际的shell和非gnu userland命令。首先,编写代码并没有那么容易,但是至少不会受到愚蠢的维护者引入的随机错误的困扰,这些愚蠢的维护者不知道向后兼容性。