提取键值

提取键值

我想要一个简单的脚本,让我可以向它传递任何文本,并从字符串中提取键的值。

我希望它能够灵活地接受 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: 任何空白字符。

这并没有尝试解决像\xjson 中的编码、引号内引号嵌入这样的极端情况(根据语言的不同,做法也有所不同)。它不允许 或 两侧有:空格=。如果需要的话,所有这些都可以解决。这将取决于您尝试处理的确切输入的类型。

答案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

相关内容