Return 数字范围内低于字符串模式匹配的值
Return Values Below String Pattern Match in Number Range
我需要匹配和 return 以下文本文件的第一个 line/row (UTC) 中低于数字范围 12-00 的值:
UTC 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 00 01 02 03 04 05 06
TMP 54 53 52 50 49 48 47 47 47 48 48 48 48 48 47 45 44 43 43 41 40 39 38 37 36
也就是说,匹配第 1 行中的 12 13 14 15 16 17 18 19 20 21 22 23 00
和第 2 行中的 returning 47 47 47 48 48 48 48 48 47 45 44 43 43
。
我的尝试:
cat some.text.file | head -n 3 | grep -A 1 '12.*.00' | tail -n 1
结果:
TMP 54 53 52 50 49 48 47 47 47 48 48 48 48 48 47 45 44 43 43 41 40 39 38 37 36
预期结果:
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
这可以一次性完成 awk
:
awk 'NR == 1 {for (i=1; i<=NF; ++i) if ($i == "12") start = i; else if ($i == "00") stop = i} {for (i=start; i<=stop; ++i) printf "%s", $i (i < stop ? OFS : ORS)}' file
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
更具可读性的版本:
awk 'NR == 1 {
for (i=1; i<=NF; ++i)
if ($i == "12")
start = i
else if ($i == "00")
stop = i
}
{
for (i=start; i<=stop; ++i)
printf "%s", $i (i < stop ? OFS : ORS)
}' file
我将按如下方式使用 GNU AWK
完成此任务,令 file.txt
内容为
UTC 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 00 01 02 03 04 05 06
TMP 54 53 52 50 49 48 47 47 47 48 48 48 48 48 47 45 44 43 43 41 40 39 38 37 36
然后
awk '/^UTC/{match([=11=],"12 13 14 15 16 17 18 19 20 21 22 23 00")}{print substr([=11=],RSTART,RLENGTH)}' file.txt
输出
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
说明:我使用 2 functions for working with strings 即 match
它确实设置了 RSTART
和 RLENGTH
,然后 substr
得到那部分线或部分在它下面。第一个动作仅限于以 UTC
开头的行,第二个动作适用于所有行。
免责声明:此解决方案假定必须事先知道必须匹配的字符串
(在 gawk 4.2.1 中测试)
一般来说,对于这样的问题,您希望根据输入字段的某些映射输出一组字段,我发现最好创建一个数组,将输出字段编号映射到输入字段编号(out2in[]
下面)然后遍历该数组:
$ cat tst.awk
NR == 1 {
for (inFldNr=2; $inFldNr!=0; inFldNr++) {
if ( $inFldNr >= 12 ) {
out2in[++numOutFlds] = inFldNr
}
}
out2in[++numOutFlds] = inFldNr
}
{
for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) {
inFldNr = out2in[outFldNr]
printf "%s%s", $inFldNr, (outFldNr<numOutFlds ? OFS : ORS)
}
}
$ awk -f tst.awk file
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
上面假设在输入的第一行总是有一个终止字段编号00
,如果不是这种情况,只需调整逻辑来处理它。
这可能适合您 (GNU sed):
sed -E 's/\s*$//;N;:a;/^12/!s/^.(.*\n).//;ta;/00\n/!s/.(\n.*).//;ta' file
启用扩展正则表达式 -E
。
Trim第一行末尾的空格。
追加下一行。
如果第一行的开头不是12
,则从两行的开头删除一个字符。
如果第一行的末尾不是00
,则从两行的末尾删除一个字符。
打印结果。
我需要匹配和 return 以下文本文件的第一个 line/row (UTC) 中低于数字范围 12-00 的值:
UTC 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 00 01 02 03 04 05 06
TMP 54 53 52 50 49 48 47 47 47 48 48 48 48 48 47 45 44 43 43 41 40 39 38 37 36
也就是说,匹配第 1 行中的 12 13 14 15 16 17 18 19 20 21 22 23 00
和第 2 行中的 returning 47 47 47 48 48 48 48 48 47 45 44 43 43
。
我的尝试:
cat some.text.file | head -n 3 | grep -A 1 '12.*.00' | tail -n 1
结果:
TMP 54 53 52 50 49 48 47 47 47 48 48 48 48 48 47 45 44 43 43 41 40 39 38 37 36
预期结果:
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
这可以一次性完成 awk
:
awk 'NR == 1 {for (i=1; i<=NF; ++i) if ($i == "12") start = i; else if ($i == "00") stop = i} {for (i=start; i<=stop; ++i) printf "%s", $i (i < stop ? OFS : ORS)}' file
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
更具可读性的版本:
awk 'NR == 1 {
for (i=1; i<=NF; ++i)
if ($i == "12")
start = i
else if ($i == "00")
stop = i
}
{
for (i=start; i<=stop; ++i)
printf "%s", $i (i < stop ? OFS : ORS)
}' file
我将按如下方式使用 GNU AWK
完成此任务,令 file.txt
内容为
UTC 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 00 01 02 03 04 05 06
TMP 54 53 52 50 49 48 47 47 47 48 48 48 48 48 47 45 44 43 43 41 40 39 38 37 36
然后
awk '/^UTC/{match([=11=],"12 13 14 15 16 17 18 19 20 21 22 23 00")}{print substr([=11=],RSTART,RLENGTH)}' file.txt
输出
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
说明:我使用 2 functions for working with strings 即 match
它确实设置了 RSTART
和 RLENGTH
,然后 substr
得到那部分线或部分在它下面。第一个动作仅限于以 UTC
开头的行,第二个动作适用于所有行。
免责声明:此解决方案假定必须事先知道必须匹配的字符串
(在 gawk 4.2.1 中测试)
一般来说,对于这样的问题,您希望根据输入字段的某些映射输出一组字段,我发现最好创建一个数组,将输出字段编号映射到输入字段编号(out2in[]
下面)然后遍历该数组:
$ cat tst.awk
NR == 1 {
for (inFldNr=2; $inFldNr!=0; inFldNr++) {
if ( $inFldNr >= 12 ) {
out2in[++numOutFlds] = inFldNr
}
}
out2in[++numOutFlds] = inFldNr
}
{
for (outFldNr=1; outFldNr<=numOutFlds; outFldNr++) {
inFldNr = out2in[outFldNr]
printf "%s%s", $inFldNr, (outFldNr<numOutFlds ? OFS : ORS)
}
}
$ awk -f tst.awk file
12 13 14 15 16 17 18 19 20 21 22 23 00
47 47 47 48 48 48 48 48 47 45 44 43 43
上面假设在输入的第一行总是有一个终止字段编号00
,如果不是这种情况,只需调整逻辑来处理它。
这可能适合您 (GNU sed):
sed -E 's/\s*$//;N;:a;/^12/!s/^.(.*\n).//;ta;/00\n/!s/.(\n.*).//;ta' file
启用扩展正则表达式 -E
。
Trim第一行末尾的空格。
追加下一行。
如果第一行的开头不是12
,则从两行的开头删除一个字符。
如果第一行的末尾不是00
,则从两行的末尾删除一个字符。
打印结果。