我想要一个简单的脚本,让我可以向它传递任何文本,并从字符串中提取键的值。
我希望它能够灵活地接受 XML 或 JSON 输入,甚至是格式不正确的输入,例如日志中的文本。
例如,给定以下任何输入,它应该能够提取test
密钥的值。
例如
$ echo "test:5 hi there" | extract_key_value test
应该导致
5
请注意,我不关心它是用什么写的,所以 node、ruby 等对我来说没问题,但可移植性(Linux/osx)很好;-)
输入1
this is test:5 i saw a value
输入2
this is test:'another value' i saw a value
输入3
this is test=5 i saw a value
输入4
test='a string value here'
输入5
my data
on line 2 test='a string value here'
more data
我对此的快速破解如下,我觉得可以大大改进,并且感觉应该在某个地方解决它!
提取键值
#!/usr/bin/env bash
function show_help()
{
IT=$(cat <<EOF
Helps you extract a key value from a string, typically a log msg
usage: key {keyBeginDelim} {keyEndDelim}
e.g. given "asd f asdf asdf test=easy asdf me=you" as input
extract_key_value test
=> returns easy
EOF
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$1" ]
then
show_help
fi
INPUT=$(cat -)
KEY="$1"
function getVal()
{
DELIM1="$1"
DELIM2="$2"
echo "$INPUT" | awk -F "$DELIM1" '{print $2}' | awk -F "$DELIM2" '{print $1}'
}
# Try whatever the user passed in or defaults for delims
if [ -n "$2" ]
then
IT=$(getVal "$2" "$3")
fi
# Try other use cases
if [ -z "$IT" ]
then
IT=$(getVal "$KEY:'" "'")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY='" "'")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY=\"" "\"")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY:\"" "\"")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY:" " ")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY=" " ")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY=" ";")
fi
if [ -z "$IT" ]
then
IT=$(getVal "$KEY:" ";")
fi
echo "$IT"
答案1
和pcregrep
:
extract_key_value() {
pcregrep -Mo1 "(?sx)
(?:
\Q$1\E # key literally
| \"\Q$1\E\" # same in double quotes
| '\Q$1\E' # same in single quotes
)
[=:]
(?| # branch reset
'(.*?)'
| \"(.*?)\"
| ([^\"'\s]+)
)"
}
-M
:多行匹配(允许test:'foo\nbar'
...)-o1
:输出第一个捕获组匹配的文本(见下文分支重置)。(?sx)
:启用s
标志(.
也匹配换行符)和x
标志(允许带有注释格式的多行)\Q$1\E
(函数的第一个参数)的内容$1
应按字面意思理解。假设它不包含\E
自身。在类似于 ksh93 的 shell 中bash
,您可以替换$1
为 来${1//\\E/\\E\\\\E\\Q}
解决这个问题。(?|.(.).|.(.).)
分支重置。捕获组的编号在每个之后从 1 开始|
,因此-o1
将返回在任何交替中匹配的第一个捕获组。'.*?'
。.*?
是 的非贪婪变体.*
,因此'.*'
将匹配从'
到之后的第一个'
。\s
: 任何空白字符。
这并没有尝试解决像\x
json 中的编码、引号内引号嵌入这样的极端情况(根据语言的不同,做法也有所不同)。它不允许 或 两侧有:
空格=
。如果需要的话,所有这些都可以解决。这将取决于您尝试处理的确切输入的类型。
答案2
grep 的一个例子:
function extract_key_value() {
egrep -o "$1[:=]['\"[:alnum:]]+" | egrep -o "['\"[:alnum:]]+$" | egrep -o "[[:alnum:]]+"
}
echo -e "on line 1\ntest:123 asasas\non line 3\ntest='abc'\non line 5" | extract_key_value test