使用自定义排序顺序在Unix中对字母数字字符串进行排序
我有一个名称的列表,这些名称是乱序的。我怎样才能得到他们在正确的字母数字顺序,使用定制排序为字母部分?使用自定义排序顺序在Unix中对字母数字字符串进行排序
我的文件numbers.txt
:
alpha-1
beta-3
alpha-10
beta-5
alpha-5
beta-1
gamma-7
gamma-1
delta-10
delta-2
主要的一点是,我的脚本应该认识到,应该beta
之前打印alpha
,并beta
gamma
面前,gamma
delta
之前。
也就是说,单词应该根据它们代表的希腊字母中的字母顺序排序。
预期的顺序:
alpha-1
alpha-5
alpha-10
beta-1
beta-3
beta-5
gamma-1
gamma-7
delta-2
delta-10
PS:我试图与sort -n numbers.txt
,但它不适合我的需要。
您可以使用指令如下:
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
位于排序键的有序列表中的位置。
sort
然后排序awk
的输出由映射号码,以及原来的号码在第2列,从而产生所需的自定义排序顺序。cut
然后删除aux。再次映射数字。
请参阅我的新问题:http://stackoverflow.com/questions/41835799/sort-a-find-command-to-respect-a-custom- order-in-unix – Daniel
通用的解决方案: 排序-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
如果你有机会获得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/'
这有效,但由于多个'sed'命令,效率非常低;请注意,您可以将它们全部组合到一个_single_'sed'脚本中,'''调用由''分隔;' 您不需要在输入中填充数字以实现数字排序;相反,使用'sort'和'-n'选项(字段选择性):'sort -t- -k 1,1n -k 2,2n'。 如果您在排序之前没有使用数字映射替换单词,但将_映射的数字作为(临时)第一个字段添加到_prepended_,那么您只需要使用 即可在排序之后使用'cut - d- -f2-' - 不再需要'sed' – mklement0
我会在这里找到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} = [email protected]_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
,让您的有序输出。
有人抱怨说Perl不容易破译? ;) –
我不觉得比其他答案中的Python代码更难阅读,但我添加了内联评论以帮助易读。 –
这是一个Python解决方案。不要试图用Bash,sed,awk做很多事情。通常你可以完成你想要的任务,但它会更混乱,更容易出错,而且难以维护。
#!/usr/bin/env python3
# Read input lines
use_stdin = True
if use_stdin:
import sys
lines = sys.stdin.read().strip().split()
else:
# for testing
with open('numbers.txt') as input:
lines = input.read().strip().split()
# Create a map from greek letters to integers for sorting
greek_letters = """alpha beta gamma delta epsilon zeta
eta theta iota kappa lambda mu
nu xi omicron pi rho sigma
tau upsilon phi chi psi omega"""
gl = greek_letters.strip().split()
gl_map = {letter:rank for rank, letter in enumerate(gl)}
# Split each line into (letter, number)
a = (x.split('-') for x in lines)
b = ((s, int(n)) for s,n in a)
# Using an order-preserving sort, sort by number, then letter
by_number = lambda x: x[1]
by_greek_letter = lambda x: gl_map.get(x[0])
c = sorted(sorted(b, key=by_number), key=by_greek_letter)
# Re-assemble and print
for s,n in c:
print('-'.join((s, str(n))))
[排序多个密钥对Unix排序(http://stackoverflow.com/questions/357560/sorting-multiple-keys-with-unix-sort) –
正如前面所说的可能的复制,主要点是有一个特定的顺序来尊重(alpha,beta,gamma和delta)。我认为'sort -k'不会解决这个问题。没有? – Daniel
我现在看到的更清楚你想做什么,不幸的是,用简单的'sort'并不是真的可以做到。有可能使用'awk',但最好的解决方案可能是创建一个程序(例如Python)来进行排序。 –