我只需要使用 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
- 第一个
tr
将输入数据中的所有行转换为一列。原始行在其输出中由空行(两个换行符)分隔。 - 按相反的字典顺序
awk
分别对每组行进行排序(以便“顺序”排在第一位)。 - 第二个
tr
与以下内容一起sed
将行重新组合在一起,但现在列已按排序顺序排列。只是tr
用一个字符替换所有换行符|
,而在找到sed
字符串的地方断行。|Order
- 最后一个
sed
与我原来的解决方案类似,但只是从线条中捕获了更多内容。 - 最后的
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
,sed
或tr
,并且绝对想要一个 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