5

文件:

timestamp1 KKIE ABC=123 [5454] GHI=547 JKL=877 MNO=878      
timestamp2 GGHI ABC=544 [ 24548] GHI=883 JKL=587 MNO=874    
timestamp3 GGGIO ABC=877 [3487] GHI=77422 JKL=877 MNO=877    
timestamp4 GGDI ABC=269 [ 1896] GHI=887 JKL=877 MNO=123

注意:有时'['和下一个数字之间有一个空格)。

当 JKL=877 时,我想要 timestampx、ABC 和 GHI

解决方案1:

timestamp1 ABC=123 GHI=547
timestamp3 ABC=877 GHI=77422
timestamp4 ABC=269 GHI=887 

解决方案2(最好的一个):

TIMESTAMP   ABC GHI

timestamp1  123 547

timestamp3  877 77422

timestamp4  269 887

我知道如何单独拥有这些值,但不是一次拥有所有这些值。

A.解决方案1:

grep JKL=877 file | awk '{print $1}'  
grep JKL=877 file | grep -o '.ABC=[0-9]\{3\}'
grep JKL=877 file | grep -o '.GHI=[0-9]\{3,5\}'

没有'['问题,我会这样做:

grep JKL=877 | awk '{print $1,$3,$5}' file  

B. 对于解决方案 2:

grep JKL=877 file | grep -o '.ABC=[0-9]\{3\}' | tr 'ABC=' ' ' | awk '{print $1}'

(我使用 awk 来删除 tr 函数创建的空间)

grep JKL=877 file | grep -o '.GHI=[0-9]\{3,5\}' | tr 'ABC=' ' ' | awk '{print $1}'

没有'['问题,我会这样做:

printf "TIMESTAMP       ABC       GHI\n";
awk '{print $1,$3,$5}' file | tr 'ABC=' ' ' | tr 'GHI=' ' ' 

C. 现在要将它们全部放入一次,我正在考虑一个循环并将匹配项放入一个变量中(请参阅https://unix.stackexchange.com/questions/37313/how-do-i-grep-for-multiple-模式): MATCH=".ABC=[0-9]\{3\} .GHI=[0-9]\{3,5\}"但我的语法有问题;此外,它不包括timestampx。

printf "TIMESTAMP       ABC       GHI\n"
grep JKL=877 file | while read line
do
?
done 

感谢您的帮助。

4

8 回答 8

6

尝试使用sed

printf "TIMESTAMP\tABC\tGHI\n"

sed -nr '/JKL=877/s/^(\w+).*ABC=([0-9]+).*GHI=([0-9]+).*/\1\t\2\t\3/p' file

输出:

TIMESTAMP   ABC GHI
timestamp1  123 547
timestamp3  877 77422
timestamp4  269 887
于 2013-11-01T18:13:52.657 回答
2

对于这些类型的问题,通常最好先构建一个数组,将名称映射到name=value字段类型的值。这样,您可以通过使用名称寻址数组来简单地使用字段值:

$ cat file
timestamp1 KKIE ABC=123 [5454] GHI=547 JKL=877 MNO=878
timestamp2 GGHI ABC=544 [ 24548] GHI=883 JKL=587 MNO=874
timestamp3 GGGIO ABC=877 [3487] GHI=77422 JKL=877 MNO=877
timestamp4 GGDI ABC=269 [ 1896] GHI=887 JKL=877 MNO=123
$
$ cat tst.awk
{
    for (i=1;i<=NF;i++) {
        split($i,tmp,/=/)
        val[tmp[1]] = tmp[2]
        fld[tmp[1]] = $i
    }

    if (val["JKL"] == 877) {
        print $1, fld["ABC"], fld["GHI"]
    }
}
$
$ awk -f tst.awk file
timestamp1 ABC=123 GHI=547
timestamp3 ABC=877 GHI=77422
timestamp4 ABC=269 GHI=887
于 2013-11-02T14:11:33.200 回答
1
#!/bin/bash
cat input.txt
echo ""
echo "############"
echo "TIMESTAMP   ABC GHI"
sed -ne 's/\(timestamp[0-9]\).*ABC=\([0-9]*\).*GHI=\([0-9]*\).*JKL=877.*$/\1 \2 \3/gp' input.txt

输出是

timestamp1 KKIE ABC=123 [5454] GHI=547 JKL=877 MNO=878      
timestamp2 GGHI ABC=544 [ 24548] GHI=883 JKL=587 MNO=874    
timestamp3 GGGIO ABC=877 [3487] GHI=77422 JKL=877 MNO=877    
timestamp4 GGDI ABC=269 [ 1896] GHI=887 JKL=877 MNO=123
############
TIMESTAMP   ABC GHI
timestamp1 123 547
timestamp3 877 77422
timestamp4 269 887

如果您不使用它们之间的东西[然后]忽略它们

于 2013-11-01T18:00:53.883 回答
1

这是一个 awk 版本:

awk -F'=| +' -v OFS=$'\t' 'BEGIN {
    print "TIMESTAMP", "ABC", "GHI"
}{
    sub(/\[[^]]+\]/, "");
    if ($8==877) print $1, $4, $6
}' input-file
于 2013-11-01T18:19:34.097 回答
1

使用

$ perl -lne '
    print "$1 $2 $3"
        if m/^(timestamp\d+).*?(ABC=\d+).*?(GHI=\d+)\s+JKL=877/i
' file

输出

timestamp1 ABC=123 GHI=547
timestamp3 ABC=877 GHI=77422
timestamp4 ABC=269 GHI=887
于 2013-11-01T19:37:04.403 回答
0

如果您可以对输入的顺序和字段的数量做出一些假设,例如末尾行没有空格,您可以使用您在“解决方案 2”中尝试的简单字段引用,例如:

awk '/JKL=877/ { print $1, $4, $(NF==11 ? 7 : 8) }' FS='=| +' file

输出:

timestamp1 123 547            
timestamp3 877 77422
timestamp4 269 887
于 2013-11-04T09:13:40.827 回答
0

如果一行上的匹配数是恒定的,您可以在以下帮助下使用仅 grep 的解决方案paste

grep JKL=877 file |
grep -o -e '^timestamp[0-9]' -e '\bABC=[0-9]\{3\}' -e '\bGHI=[0-9]\{3,5\}' |
grep -o '[^=]*$'  |
paste - - -

输出:

timestamp1  123 547
timestamp3  877 77422
timestamp4  269 887

要包含所需的标题,请执行以下操作:

(
  printf "TIMESTAMP\tABC\tGHI\n"
  grep JKL=877 file |
  grep -o -e '^timestamp[0-9]' -e '\bABC=[0-9]\{3\}' -e '\bGHI=[0-9]\{3,5\}' |
  grep -o '[^=]*$'  |
  paste - - -
)

输出:

TIMESTAMP   ABC GHI
timestamp1  123 547
timestamp3  877 77422
timestamp4  269 887
于 2013-11-04T08:47:55.983 回答
0

对于解决方案 1,您可以尝试以下方法:

[ ~]$ awk 'BEGIN {str=""}{str=str"\n"; for (i=1;i<=NF;i++){if($i ~ "^(timestamp\(ABC|GHI)=)"){str=str""$i" "}}} END {print str}' file.txt|sed "1d;s/\ $//g"
timestamp1 ABC=123 GHI=547
timestamp2 ABC=544 GHI=883
timestamp3 ABC=877 GHI=77422
timestamp4 ABC=269 GHI=887

如果您需要捕获与模式 "[AZ]+=[0-9]+" 匹配的所有值:

[ ~]$ awk 'BEGIN {str=""} {str=str"\n"; for (i=1;i<=NF;i++){if($i ~ "^(timestamp|[A-Z]+=[0-9]+)"){str=str""$i" "}}} END {print str}' file.txt|sed "1d;s/\ $//g"
timestamp1 ABC=123 GHI=547 JKL=877 MNO=878
timestamp2 ABC=544 GHI=883 JKL=587 MNO=874
timestamp3 ABC=877 GHI=77422 JKL=877 MNO=877
timestamp4 ABC=269 GHI=887 JKL=877 MNO=123

对于解决方案 2:

[ ~]$ head=$(head -n1 file.txt|egrep -o "[A-Z]+=[0-9]+"|awk -F "=" 'BEGIN{s=""}{s=s""$1" "} END {print "TIMESTAMP "s}'|sed "s/\ $//g")
[ ~]$ content=$(i=1; while read; do echo $REPLY|egrep -o "[A-Z]+=[0-9]+"|awk -F "=" 'BEGIN{s=""} {s=s""$2" "} END {print "timestamp'$i' "s}'|sed "s/\ $//g"; ((i++)); done < file.txt)
[ ~]$ echo -e "$head\n$content"
TIMESTAMP ABC GHI JKL MNO
timestamp1 123 547 877 878
timestamp2 544 883 587 874
timestamp3 877 77422 877 877
timestamp4 269 887 877 123
于 2013-11-01T18:19:17.080 回答