在shell脚本中,如何按字母顺序然后按数字对第二列进行排序?
我有一个文本文件,如下所示: info.txt在shell脚本中,如何按字母顺序然后按数字对第二列进行排序?,shell,unix,Shell,Unix,我有一个文本文件,如下所示: info.txt files-550519470 19h files-1662192679 1d files-247106034 1d files-1986982365 2d files-464153317 12m files-739420408 3d files-77614277 3m files-374059185 4d files-909323637 4d files-101830442 5d files-1270496134 5d files-1797797
files-550519470 19h
files-1662192679 1d
files-247106034 1d
files-1986982365 2d
files-464153317 12m
files-739420408 3d
files-77614277 3m
files-374059185 4d
files-909323637 4d
files-101830442 5d
files-1270496134 5d
files-1797797160 6d
files-812888216 7d
files-118869238 7h
我想根据第二列字母表进行排序,在这之后,同一第二列和输出中数字的降序应如下所示:
files-812888216 7d
files-1797797160 6d
files-101830442 5d
files-101830442 5d
files-1270496134 5d
files-374059185 4d
files-909323637 4d
files-374059185 4d
files-909323637 4d
files-739420408 3d
files-1986982365 2d
files-1662192679 1d
files-247106034 1d
files-550519470 19h
files-118869238 7h
files-464153317 12m
files-77614277 3m
我可以通过下面的命令根据数字反转,但无法计算字母。有人能推荐一下吗
sort -r -nk2 info.txt
@编辑
谢谢你的帮助!我们只需:
sed 's/\(.*\) \([0-9]*\)\([a-zA-Z]*\)/\3 \2 \1 \2\3/' |
sort -k1 -k2nr |
cut -d' ' -f3-
sed
在前面添加两列新内容,一列包含第3列中的字母,第二列包含第3列中的数字sed 's/\(.*\) \([0-9]*\)\([a-zA-Z]*\)/\3 \2 \1 \2\3/' |
sort -k1 |
{
presuffix=''
buff=''
while IFS=' ' read -r suffix rest; do
if [ "$presuffix" != "$suffix" ]; then
echo -n "$buff" | sort -n -r -k1
presuffix=$suffix
buff=''
fi
buff+="$rest"$'\n'
done
printf "%s" "$buff" | sort -n -r -k1
} |
cut -d' ' -f2-
1d
,因此行的前面是d1。。。行的其余部分
。因此,该行前面有两个新列-一个按字母顺序排序,另一个按数字排序中被删除,因此它现在是第一列)
cut-d'-f2-
删除了第一列(数字),而阅读
部分,但我没有更好的想法sed 's/\(.*\) \([0-9]*\)\([a-zA-Z]*\)/\3 \2 \1 \2\3/' |
while IFS=' ' read -r suffix num rest; do
echo "$(printf "%d * 256 + (256 - %d)\n" "'$suffix" "$num" | bc)" "$rest"
done |
sort -r -n |
cut -d' ' -f2-
假设排序列中只有一个字符后缀(1d
或1e
或1h
或19d
),并且排序列中的数字小于256(幻数,可能会增加),我们可以将字符转换为ascii数字
然后我们可以将ascii数乘以256,并将排序列中的数字相加。数字被减为256,因为在每个数据块中,我们希望使用数字进行反向排序(7d
是第一个,然后是1d
)。然后我们就按数字排序
我们也可以使用printf“(256-%d)+%d”
,然后使用反向数值调用排序,只有当两个字段相等时才会出现差异(例如文件-1662192679
和文件-247106034
)
幻数256
应大于排序列中的最大数字,也应大于排序列中字符的最大ascii表示形式。可能这可以扩展到处理排序列中的多个字符。使用以下模式:
这应该比Bash循环快得多。如果您有gawk
来替换sort
和sed
如果你有GNU或BSD排序,你可以利用字母顺序
dYou在正确的轨道上,但为什么不直接转换n days=n*24*60;小时=小时*60;。。。etc
并将该值插入第一列(保留最后一列)、管道进行排序、再次管道到awk并删除第一列。如果将它们转换为整数,则反向排序将中断。想法是,字符需要按字母顺序排序d
h
m
。但小时持续时间比天持续时间小(不知道怎么说)。结果应该是:先是几天,然后是几个小时,然后是几个月。天内的数字应该进行反向排序。我想,知道每行n<100
我们可以d天=n*100**2;h=h*100;m months=n
然后进行数字排序。首先,在管道前端将时间扩展到分钟wawk
。我认为它的输出应该是1140个文件-550519470 19h
。现在可以按第一个字段对记录进行数字排序(并反转)。所以你有awk'{mins=cvrtToMins($NF);print mins“\t”$0}”inputFile | sort…..| awk'{$1=“”}
对不起,我以前不清楚。祝大家好运。啊,错过了你的| cut-d…
那也行;-)(请注意1d=1440分钟
)。当然,O.P.现在将查询以处理3d 5h 7m
以及与您使用256-%d
等相关的问题,在awk
中有许多解决方案可以解决将1d
转换为1,然后再转换为1440(分钟)
。您通常只需分配m=($NF+0)
即可删除指定字段中的所有字符。祝你好运@卡米尔库克:你需要学习如何阅读man
页面(排序非常复杂)。;-)。可以使用一系列修饰符进一步修改指定为排序列的每个字段sort-k3-k2nr文件
首先(主要)对第3列进行排序,然后对第2列进行排序,按数字顺序进行排序,然后进行反向排序。祝大家好运!
$ sort -t $'-' -k 2 file |
sed -E 's/(.*) ([[:digit:]][[:digit:]]*)([dmh]$)/\2 \3 \1 \2\3/' |
awk 'BEGIN{arr["m"]=1; arr["h"]=60; arr["d"]=60*24}
{$2=$1*arr[$2]; $1=""; print}' |
sort -s -k1nr |
cut -d' ' -f3-
files-812888216 7d
files-1797797160 6d
files-101830442 5d
files-101830442 5d
files-1270496134 5d
files-374059185 4d
files-374059185 4d
files-909323637 4d
files-909323637 4d
files-739420408 3d
files-1986982365 2d
files-1662192679 1d
files-247106034 1d
files-550519470 19h
files-118869238 7h
files-464153317 12m
files-77614277 3m
$ sed -E 's/([^-]*)-(.*) ([[:digit:]][[:digit:]]*)([dmh]$)/\2 \4 \3 \1-\2 \3\4/' file |
sort -s -t $' ' -k2,2 -k3,3nr -k1,1 |
cut -d $' ' -f4-
# same output