在具有多个部分的文件的一个部分中查找字符串

在具有多个部分的文件的一个部分中查找字符串

如何使用 sed/awk 获取另一个字符串中包含的字符串。

TESTVAR='
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID",
 version : 79
}
,
{
 icon : "thisicon",
 id : 8080,
 initialState : false,
 isPng : true,
 label : "Boundaries",
 opacity : 1,
 requestType : "NothingSpecial",
 version : 8
}

version : 79我需要为包含 的对象选择requestType : "UUID"。我如何选择第一个块内的所有内容,然后选择版本,然后只使用命令 return 79。我已经尝试了一段时间,但不知道如何只选择第一个之间的所有内容{}。一旦我有了这个,我就只需要得到之后的号码version :

我以为这会起作用,但事实并非如此awk '/\{/{f=1;next}/\}/{f=0}f' test.txt

此外,订单无法保证。所以我真的需要选择里面包含“UUID”的所有{内容}。然后选择version : \([0-9]+\)

这很接近但太贪心了:sed -e 's/{\(.*UUID.*\)}/\1/' test.txt

答案1

首先我想到的既不是 sed 也不是 awk:

$ tr -d '\n' < file | grep -Po 'requestType : "UUID"\K.*? version : \K[0-9]*'
79

可能可以更容易地完成,特别是如果您可以保证“version”紧随“requestType”之后。

如果version不需要让requested Type事情变得更复杂一点:

$ tr -d '\n' < file | grep -Po '{.[^}]*?requestType : "UUID".*?}' | grep -Po 'version : \K[0-9]*'
79

如果有更多可以匹配所有部分的部分将被打印:

$ cat file
TESTVAR='
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 version : 79,
 requestType : "UUID"
}
,
{
 icon : "thisicon",
 id : 8080,
 initialState : false,
 isPng : true,
 label : "Boundaries",
 opacity : 1,
 requestType : "NothingSpecial",
 version : 8
}
,
{
 icon : "icons/773_l.png",
 id : 80,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID",
 version : 87
}
,
{
 icon : "icons/773_l.png",
 id : 80,
 version : 17,
 initialState : true,
 isPng : false,
 label : "Imagery",
 opacity : 1,
 requestType : "UUID"
}
,
{
 icon : "thisicon",
 id : 8080,
 requestType : "NothingSpecial",
 initialState : false,
 label : "Boundaries",
 opacity : 1,
 version : 18,
 isPng : true
}

$ tr -d '\n' < file | grep -Po '{.[^}]*?requestType : "UUID".*?}' | grep -Po 'version : \K[0-9]*'
79
87
17

答案2

awk 允许您定义记录分隔符,因此不要使用换行符(每行都是一条记录),而是使用“}\n”作为记录的结尾:

echo "$TESTVAR" |
gawk -v RS="}\n" '
    /requestType : "UUID"/ && match($0, /version : ([0-9]+)/, m) {print m[1]}
'
79

这是 GNU awk 特有的,用于 match() 函数。


可惜这不是有效的 JSON。然后你可以使用 JSON 解析器:

jq '(.[] | select(.requestType == "UUID")).version' <<JSON
[
 {
  "icon" : "icons/773_l.png",
  "id" : 80,
  "initialState" : true,
  "isPng" : false,
  "label" : "Imagery",
  "opacity" : 1,
  "requestType" : "UUID",
  "version" : 79
 }
 ,
 {
  "icon" : "thisicon",
  "id" : 8080,
  "initialState" : false,
  "isPng" : true,
  "label" : "Boundaries",
  "opacity" : 1,
  "requestType" : "NothingSpecial",
  "version" : 8
 }
]
JSON

答案3

这是纯粹使用以下方法来做到这一点的一种方法sed

$ sed -rn '/\{/{:a;N;/\}/{/requestType : "UUID"/s/.*version : ([0-9]+).*/\1/p;d};ba}' <<< "$TESTVAR"
79
$ 

这是改编自https://stackoverflow.com/a/18046021/2113226为了您的数据。


你提到这是一个javascript数据结构,所以我认为解析它的最可靠的方法是使用javascript。我安装了 Node.js 来执行此操作,但我认为任何命令行 javascript 解释器都应该能够执行如下操作:

$ echo "arr=[$TESTVAR]; console.log(arr.filter(function(elem) { return elem.requestType === \"UUID\"; })[0].version)" | node
79
$ 

免责声明

您必须确保这里的数据安全。我不太了解 javascript,但我认为如果输入数据字符串制作得当,代码注入是完全有可能的。

相关内容