Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在shell脚本中,如何按字母顺序然后按数字对第二列进行排序?_Shell_Unix - Fatal编程技术网

在shell脚本中,如何按字母顺序然后按数字对第二列进行排序?

在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

我有一个文本文件,如下所示:

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-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-
    
  • sed get在行的开头是
    1d
    ,因此行的前面是
    d1。。。行的其余部分
    。因此,该行前面有两个新列-一个按字母顺序排序,另一个按数字排序
  • 然后我们使用第一列(字母表)进行排序
  • 然后,我使用buffer将流拆分为单独的部分,并使用第二个字段(number)对每个部分进行反向排序(第一个字段在读取时在
    中被删除,因此它现在是第一列)
  • 然后,
    cut-d'-f2-
    删除了第一列(数字)
  • 这将是缓慢的,因为
    ,而阅读
    部分,但我没有更好的想法
  • @编辑:

    另一个受@SHEED comment影响的解决方案

    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
    然后进行数字排序。首先,在管道前端将时间扩展到分钟w
    awk
    。我认为它的输出应该是
    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