我正在使用bash并运行以下命令来获取两个令牌之间的所有文件文本(包括令牌本身):
cat /usr/java/jboss/standalone/log/server.log | sed -n
'/Starting deployment of "myproject.war"/,/Registering web context: /myproject/p'
但是,有时令牌在文件中多次出现。 如何调整上述内容,以便仅返回令牌的最后两次出现(包括令牌本身)之间的文本?
一些tic-tac-toe
怎么样。
tac /usr/java/jboss/standalone/log/server.log |
awk '/Registering web context: /myproject/{p=1;++cnt}/Starting deployment of "myproject.war"/{if(cnt==2){print $0;exit};print $0;p=0}p' |
tac
此解决方案效率不高,但更容易理解:
file='/usr/java/jboss/standalone/log/server.log'
s1='Starting deployment of "myproject.war"'
s2='Registering web context: /myproject'
sed -n '/'"$s1"'/,/'"$s2"'/p' "$file" |
tac |
awk '/'"$s1"'/ {print;exit} 1' |
tac
- 让我们先
sed
报告所有范围。
使用 tac
反转结果(在 OSX 上,使用tail -r
)。- 使用
awk
,输出所有内容,包括第一个子字符串的第一次出现,在相反的结果中,该子字符串跨越最后一个范围的末尾到最后一个范围的开始。 - 反转
awk
的输出,以正确的顺序呈现最后一个范围。
注意:为了与 sed
命令中的变量使用保持一致,我也将变量引用直接拼接到awk
程序中,否则这种做法很糟糕(使用 -v
来传递变量)。
你可以在原生 bash 中做到这一点——不需要 awk、tac 或任何其他外部工具。
token1='Starting deployment of "myproject.war"'
token2='Registering web context: /myproject/'
writing=0
while read -r; do
(( ! writing )) && [[ $REPLY = $token1 ]] && {
# start collecting content, into an empty buffer, when we see token1
writing=1 # set flag to store lines we see
collected_content=() # clear the array of lines found so far
}
(( writing )) && {
# when the flag is set, collect content into an array
collected_content+=( "$REPLY" )
}
[[ $REPLY = $token2 ]] && {
# stop collecting content when we see token2
writing=0
}
done <server.log # redirect from the log into the loop
# print all collected lines
printf '%sn' "${collected_content[@]}"
这个尴尬可以工作:
awk '/Starting deployment of "myproject.war"/{i=0; s=1; delete a;}
s{a[++i]=$0}
/Registering web context: /myproject/{s=0}
END {print i; for (k=1; k<=i; k++) print a[k]}' file
带perl
:
perl -0xFF -nE '@x = /WWWW Starting deployment of "myproject.war"(.*?)Registering web context: /myproject/sg; say $x[-1] ' file