如何使用 sed/awk 打印匹配模式?(我可以使用 grep 做到这一点)

如何使用 sed/awk 打印匹配模式?(我可以使用 grep 做到这一点)

我只需要使用 awk 或 sed 以及 WHILE 循环来打印 11 标签。

Order:479959,60=20130624-09:45:02.046|35=D|11=884|38=723|21=1|1=30532|10=085|59=0|114=Y|56=MBT|40=1|43=Y|100=MBTX|55=/GCQ3|49=11342|54=1|8=FIX.4.4|34=388|553=2453|9=205|52=20130624-09:45:02.046|
Order:24780,100=MBTX|43=Y|40=1|34=388|553=2453|52=2013062409:45:02.046|9=205|49=11342|54=1|8=FIX.4.4|55=/GCQ3|11=405|35=D|60=20130624-09:45:02.046|56=MBT|59=0|114=Y|10=085|21=1|38=470|1=30532|
Order:799794,55=/GCQ3|49=11342|54=1|8=FIX.4.4|34=388|553=2453|9=205|52=2013062409:45:02.046|40=1|43=Y|100=MBTX|38=350|21=1|1=30532|10=085|59=0|114=Y|56=MBT|60=20130624-09:45:02.046|35=D|11=216|
Order:72896,11=735|35=D|60=2013062409:45:02.046|56=MBT|59=0|114=Y|10=085|1=30532|38=17|21=1|100=MBTX|43=Y|40=1|553=2453|9=205|52=20130624-09:45:02.046|34=388|8=FIX.4.4|54=1|49=11342|55=/GCQ3|

输出应该是这样的:-

Orderid-479959 38= 723 Clientid=884
Orderid-24780 38= 470 Clientid=405
Orderid-799794 38= 350 Clientid=216

答案1

不需要循环:

$ sed 's/^.*[,|]11=\([^|]*\).*$/client id = \1/' data.in
client id = 884
client id = 405
client id = 216
client id = 735

编辑脚本将查找11标签(11=前面有|,),并将整行替换为文本client id =,后跟数字11=(实际上任何事物跟随11=到行的 a|或行尾)。

更新(在新问题规范之后):

这是uglyscript.sh(需要 GNUsed和 GNU awk):

#!/bin/sh
tr ',|' '\n' |
awk -vRS="\n\n" '{ print | "sort -r"; close("sort -r") }' |
tr '\n' '|' |
sed 's/|Order/\nOrder/g' |
sed 's/^Order:\([^|]*\).*|\(38=[^|]*\).*|11=\([^|]*\).*$/Orderid-\1 \2 Clientid=\3/'
echo
  1. 第一个tr将输入数据中的所有行转换为一列。原始行在其输出中由空行(两个换行符)分隔。
  2. 按相反的字典顺序awk分别对每组行进行排序(以便“顺序”排在第一位)。
  3. 第二个tr与以下内容一起sed将行重新组合在一起,但现在列已按排序顺序排列。只是tr用一个字符替换所有换行符|,而在找到sed字符串的地方断行。|Order
  4. 最后一个sed与我原来的解决方案类似,但只是从线条中捕获了更多内容。
  5. 最后的echo只是确保输出末尾有一个换行符。

由于列未排序,因此需要执行上述步骤 1 至 3。11=例如,包含的列可以出现在线路上的任何位置,这使得通过单个sed脚本运行它变得非常困难。

第 3 步之后的数据如下所示:

Order:479959|9=205|8=FIX.4.4|60=20130624-09:45:02.046|59=0|56=MBT|55=/GCQ3|553=2453|54=1|52=20130624-09:45:02.046|49=11342|43=Y|40=1|38=723|35=D|34=388|21=1|1=30532|11=884|114=Y|10=085|100=MBTX
Order:24780|9=205|8=FIX.4.4|60=20130624-09:45:02.046|59=0|56=MBT|55=/GCQ3|553=2453|54=1|52=2013062409:45:02.046|49=11342|43=Y|40=1|38=470|35=D|34=388|21=1|1=30532|11=405|114=Y|10=085|100=MBTX
Order:799794|9=205|8=FIX.4.4|60=20130624-09:45:02.046|59=0|56=MBT|55=/GCQ3|553=2453|54=1|52=2013062409:45:02.046|49=11342|43=Y|40=1|38=350|35=D|34=388|21=1|1=30532|11=216|114=Y|10=085|100=MBTX
Order:72896|9=205|8=FIX.4.4|60=2013062409:45:02.046|59=0|56=MBT|55=/GCQ3|553=2453|54=1|52=20130624-09:45:02.046|49=11342|43=Y|40=1|38=17|35=D|34=388|21=1|1=30532|11=735|114=Y|10=085|100=MBTX|

运行它:

$ ./uglyscript.sh <data.in
Orderid-479959 38=723 Clientid=884
Orderid-24780 38=470 Clientid=405
Orderid-799794 38=350 Clientid=216
Orderid-72896 38=17 Clientid=735

答案2

一个“干净”的 awk 解决方案

如果您感兴趣的话,可以使用一些awk具有格式化输出版本的一次性命令(尽管这看起来是一项非常适合的工作sed):

awk -F'\\||,' '{
                   for (i=1;i<NF+1;i++) {
                     if ($i ~ /11=.*/) {
                       split($i, a, "=")                           
                     }
                     if ($i ~ /Order:.*/) {
                       split($i, b, ":")
                     }
                     if ($i ~ /38=.*/) {
                       split($i, c, "=")
                     }
                   }
                   printf "Orderid-%-10s 38= %-8s Clientid=%s\n", b[2], c[2], a[2]
                 }' < infile.txt

如果您非常不想使用awk,sedtr,并且绝对想要一个 shell while 循环,请注意,正如评论中已经说过的那样,这是一个非常糟糕的做法。有广泛的解释为什么太糟糕了这里


“不要这样做”的解决方案

现在我们已经做出了这个小小的免责声明,这里有一种在 while 循环中仅使用 bash 字符串操作来实现输出的方法(脚本形式,当然它只适用于 bash):

while read line; 
do
  x=${line#*11=}
  x=${x%%|*}
  y=${line#*:}
  y=${y%%,*}
  z=${line#*38=}
  z=${z%%|*}
  echo "Orderid-$y 38= $z Clientid=$x"
done < infile.txt

在你的特定示例中它有效,但是不要在“现实生活”的情况下这样做。任何 shell 的基本思想都是:“对外部工具的调用越少越好”。因此,理想情况下,如果您可以像我的 awk 示例一样在一次调用中完成这项工作,那就去做吧。 awk 将被加载一次然后整个工作都是用 C 语言完成的,与 shell 相比,它快如闪电。


在我的回答中,bash 中的字符串操作是如何工作的

  • ${string#pattern}:从字符串的左侧开始,删除最短匹配模式。因此,如果你放置一个像这样的模式*a,则一切都取决于第一的“a”字符(包含在内)将从字符串中删除。如果您使用相同的语法但使用 2 个“#”,则 for 的匹配pattern将变得尽可能贪婪,并删除字符串中直到最后一个“a”字符的所有内容。例子:

    $ test="alakazam"; echo ${test#*a}; echo ${test##*a};
    lakazam
    m
    
  • ${string%pattern}: 工作原理相同,但从右侧进行。用前面的例子来说明:

    $ test="alakazam"; echo ${test%a*}; echo ${test%%a*};
    alakaz
                 #no output here: the whole string is matched by pattern
    

相关内容