如何按持续时间列对文件进行排序?

mer*_*nan 3 sort timestamps

如何对包含以下内容的文件进行排序?(s=秒,h=小时,d=天 m=分钟)

1s
2s
1h
2h
1m
2m
2s
1d
1m
Run Code Online (Sandbox Code Playgroud)

Hau*_*ing 6

awk '{ unitvalue=$1; }; 
    /s/ { m=1 }; /m/ { m=60 }; /h/ { m=3600 }; /d/ { m=86400 }; 
    { sub("[smhd]","",unitvalue); unitvalue=unitvalue*m; 
    print unitvalue " " $1; }' input |
        sort -n | awk '{ print $2 }'
1s
2s
2s
1m
1m
2m
1h
2h
1d
Run Code Online (Sandbox Code Playgroud)


Min*_*Max 5

第一个版本 - 使用 FPAT

gawk '
BEGIN {
    FPAT="[0-9]+|[smhd]";
}
/s/ { factor = 1 }
/m/ { factor = 60 }
/h/ { factor = 3600 }
/d/ { factor = 86400 }
{
    print $1 * factor, $0;
}' input.txt | sort -n | awk '{print $2}'
Run Code Online (Sandbox Code Playgroud)

FPAT - 描述记录中字段内容的正则表达式。设置后,gawk 将输入解析为字段,其中字段与正则表达式匹配,而不是使用FS变量的值作为字段分隔符。

第二版

我惊讶地发现,没有FPAT它也能工作。它是由awk- How awk Converts Within Strings and Numbers的数字转换机制引起的,即:

通过将字符串的任何数字前缀解释为数字,将字符串转换为数字:“2.5”转换为 2.5,“1e3”转换为 1,000,而“25fix”的数值为 25。 无法解释的字符串作为有效数字转换为零。

gawk '
/s/ { factor = 1 }
/m/ { factor = 60 }
/h/ { factor = 3600 }
/d/ { factor = 86400 }
{
    print $0 * factor, $0;
}' input.txt | sort -n | awk '{print $2}'
Run Code Online (Sandbox Code Playgroud)

输入(略有变化)

1s
122s
1h
2h
1m
2m
2s
1d
1m
Run Code Online (Sandbox Code Playgroud)

输出

注: 122 秒多于 2 分钟,所以在 2m 后排序。

1s
2s
1m
1m
2m
122s
1h
2h
1d
Run Code Online (Sandbox Code Playgroud)


Dav*_*ter 5

这是MiniMax\xe2\x80\x99 答案的扩展,可以处理更广泛的持续时间值,例如1d3h10m40s.

\n

parse-times.awkGNU Awk 程序(为了这个答案而存储):

\n\n
#!/usr/bin/gawk -f\nBEGIN{\n  FPAT = "[0-9]+[dhms]";\n  duration["s"] = 1;\n  duration["m"] = 60;\n  duration["h"] = duration["m"] * 60;\n  duration["d"] = duration["h"] * 24;\n}\n\n{\n  t=0;\n  for (i=1; i<=NF; i++)\n    t += $i * duration[substr($i, length($i))];\n  print(t, $0);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

调用:

\n
gawk -f parse-times.awk input.txt | sort -n -k 1,1 | cut -d \' \' -f 2\n
Run Code Online (Sandbox Code Playgroud)\n
\n

多列输入

\n

如果您的输入包含多列,您\xe2\x80\x99将不得不诉诸其他方法。以下代码使用函数来解析时间表达式并将结果附加为新列:

\n
#!/usr/bin/gawk -f\n# Given a time expression like "1d3h10m40s",  returns its duration in seconds.\n# If the expression doesn\'t match, returns -1.\nfunction parse_time(s) {\n    return match(s, /^(([0-9]+)w)?(([0-9]+)d)?(([0-9]+)h)?(([0-9]+)m)?(([0-9]+)s)?$/, m) ? m[10] + m[8] * 60 + m[6] * 3600 + m[4] * 86400 + m[2] * 604800 : -1;\n}\n\n{\n  $(++NF) = parse_time($1);\n  print;\n}\n
Run Code Online (Sandbox Code Playgroud)\n

然后,您可以对新列的输出进行排序,然后将其删除:

\n
gawk -f parse-times.awk input.txt | sort -n -k 2,2 | cut -d \' \' -f 1\n
Run Code Online (Sandbox Code Playgroud)\n