使用自定义排序顺序在Unix中对字母数字字符串进行排序

时间:2017-01-23 10:41:43

标签: shell sorting unix

我有一个名单清单,这些清单不正常。如何使用字母部分的自定义排序顺序以正确的字母数字顺序获取它们?

我的档案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 ,但这不符合我的需要。

6 个答案:

答案 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命令。首先,编写代码并没有那么容易,但是至少不会受到愚蠢的维护者引入的随机错误的困扰,这些愚蠢的维护者不知道向后兼容性。