我正在尝试使用diff
的{{1}}来忽略包含某些模式的行。原因是我有一个bash脚本,它使用HPE的RESTful API来检查/修补主机上的BIOS设置。当RegEx与主机上的BIOS设置匹配时,我使用--ignore-matching-lines=
来省略BIOS设置中的模式,以及我存储在变量中的设置的基本模板。如果--ignore-matching-lines=
发现设置与“黄金配置”不匹配,则会显示终端上的差异并提示应用正确的配置。我使用RegEx的设置是UEFI启动顺序和英特尔SGX设置。
这个特殊的RegEx问题围绕着SGX设置。 HPE偶尔将Epoch设置为全0的默认值。我需要确保SgxEpoch值不是全0,而是一个随机的32个字符串,就像在下面的例子中一样,或者我们在保护我们的飞地秘密时遇到了问题。
断裂:
diff
行:
"SgxEpoch": "00000000000000000000000000000000"
我做了很多观察,发现WiktorStribiżew非常有助于展示如何使用POSIX“匹配所有东西”(我发现diff不支持前瞻,因为它是BRE) - {{3 }}
所以我提出了以下ERE版本,该版本也会查找"SgxEpoch": "5FSQUWEED6XPC8PJ2CWZGQIS4WWKLKUI"
,因为这是我的比较模板的定义方式 - Regex: match everything but
"SgxEpoch": ""
然后将其转换为BRE,以便与SgxEpochRegEx='"SgxEpoch":\s*(\"([^0].{31}|.[^0].{30}|.{2}[^0].{29}|.{3}[^0].{28}|.{4}[^0].{27}|.{5}[^0].{26}|.{6}[^0].{25}|.{7}[^0].{24}|.{8}[^0].{23}|.{9}[^0].{22}|.{10}[^0].{21}|.{11}[^0].{20}|.{12}[^0].{19}|.{13}[^0].{18}|.{14}[^0].{17}|.{15}[^0].{16}|.{16}[^0].{15}|.{17}[^0].{14}|.{18}[^0].{13}|.{19}[^0].{12}|.{20}[^0].{11}|.{21}[^0].{10}|.{22}[^0].{9}|.{23}[^0].{8}|.{24}[^0].{7}|.{25}[^0].{6}|.{26}[^0].{5}|.{27}[^0].{4}|.{28}[^0].{3}|.{29}[^0].{2}|.{30}[^0].|.{31}[^0])\"|"")'
合作:
diff
以下是BRE版本捕获Epoch的非零或空白版本以及未捕获内容的示例。
SgxEpochRegEx='"SgxEpoch":\s*\("\([^0].\{31\}\|.[^0].\{30\}\|.\{2\}[^0].\{29\}\|.\{3\}[^0].\{28\}\|.\{4\}[^0].\{27\}\|.\{5\}[^0].\{26\}\|.\{6\}[^0].\{25\}\|.\{7\}[^0].\{24\}\|.\{8\}[^0].\{23\}\|.\{9\}[^0].\{22\}\|.\{10\}[^0].\{21\}\|.\{11\}[^0].\{20\}\|.\{12\}[^0].\{19\}\|.\{13\}[^0].\{18\}\|.\{14\}[^0].\{17\}\|.\{15\}[^0].\{16\}\|.\{16\}[^0].\{15\}\|.\{17\}[^0].\{14\}\|.\{18\}[^0].\{13\}\|.\{19\}[^0].\{12\}\|.\{20\}[^0].\{11\}\|.\{21\}[^0].\{10\}\|.\{22\}[^0].\{9\}\|.\{23\}[^0].\{8\}\|.\{24\}[^0].\{7\}\|.\{25\}[^0].\{6\}\|.\{26\}[^0].\{5\}\|.\{27\}[^0].\{4\}\|.\{28\}[^0].\{3\}\|.\{29\}[^0].\{2\}\|.\{30\}[^0].\|.\{31\}[^0]\)"\|""\)'
我遇到的问题是我不明白上述RegEx的工作原理。在我看来,它只是使用元字符[~]$ echo '"SgxEpoch": "5FSQUWEED6XPC8PJ2CWZGQIS4WWKLKUI"' | grep '"SgxEpoch":\s*\("\([^0].\{31\}\|.[^0].\{30\}\|.\{2\}[^0].\{29\}\|.\{3\}[^0].\{28\}\|.\{4\}[^0].\{27\}\|.\{5\}[^0].\{26\}\|.\{6\}[^0].\{25\}\|.\{7\}[^0].\{24\}\|.\{8\}[^0].\{23\}\|.\{9\}[^0].\{22\}\|.\{10\}[^0].\{21\}\|.\{11\}[^0].\{20\}\|.\{12\}[^0].\{19\}\|.\{13\}[^0].\{18\}\|.\{14\}[^0].\{17\}\|.\{15\}[^0].\{16\}\|.\{16\}[^0].\{15\}\|.\{17\}[^0].\{14\}\|.\{18\}[^0].\{13\}\|.\{19\}[^0].\{12\}\|.\{20\}[^0].\{11\}\|.\{21\}[^0].\{10\}\|.\{22\}[^0].\{9\}\|.\{23\}[^0].\{8\}\|.\{24\}[^0].\{7\}\|.\{25\}[^0].\{6\}\|.\{26\}[^0].\{5\}\|.\{27\}[^0].\{4\}\|.\{28\}[^0].\{3\}\|.\{29\}[^0].\{2\}\|.\{30\}[^0].\|.\{31\}[^0]\)"\|""\)'
"SgxEpoch": "5FSQUWEED6XPC8PJ2CWZGQIS4WWKLKUI"
[~]$ echo '"SgxEpoch": ""' | grep '"SgxEpoch":\s*\("\([^0].\{31\}\|.[^0].\{30\}\|.\{2\}[^0].\{29\}\|.\{3\}[^0].\{28\}\|.\{4\}[^0].\{27\}\|.\{5\}[^0].\{26\}\|.\{6\}[^0].\{25\}\|.\{7\}[^0].\{24\}\|.\{8\}[^0].\{23\}\|.\{9\}[^0].\{22\}\|.\{10\}[^0].\{21\}\|.\{11\}[^0].\{20\}\|.\{12\}[^0].\{19\}\|.\{13\}[^0].\{18\}\|.\{14\}[^0].\{17\}\|.\{15\}[^0].\{16\}\|.\{16\}[^0].\{15\}\|.\{17\}[^0].\{14\}\|.\{18\}[^0].\{13\}\|.\{19\}[^0].\{12\}\|.\{20\}[^0].\{11\}\|.\{21\}[^0].\{10\}\|.\{22\}[^0].\{9\}\|.\{23\}[^0].\{8\}\|.\{24\}[^0].\{7\}\|.\{25\}[^0].\{6\}\|.\{26\}[^0].\{5\}\|.\{27\}[^0].\{4\}\|.\{28\}[^0].\{3\}\|.\{29\}[^0].\{2\}\|.\{30\}[^0].\|.\{31\}[^0]\)"\|""\)'
"SgxEpoch": ""
[~]$ echo '"SgxEpoch": "00000000000000010000000000000000"' | grep '"SgxEpoch":\s*\("\([^0].\{31\}\|.[^0].\{30\}\|.\{2\}[^0].\{29\}\|.\{3\}[^0].\{28\}\|.\{4\}[^0].\{27\}\|.\{5\}[^0].\{26\}\|.\{6\}[^0].\{25\}\|.\{7\}[^0].\{24\}\|.\{8\}[^0].\{23\}\|.\{9\}[^0].\{22\}\|.\{10\}[^0].\{21\}\|.\{11\}[^0].\{20\}\|.\{12\}[^0].\{19\}\|.\{13\}[^0].\{18\}\|.\{14\}[^0].\{17\}\|.\{15\}[^0].\{16\}\|.\{16\}[^0].\{15\}\|.\{17\}[^0].\{14\}\|.\{18\}[^0].\{13\}\|.\{19\}[^0].\{12\}\|.\{20\}[^0].\{11\}\|.\{21\}[^0].\{10\}\|.\{22\}[^0].\{9\}\|.\{23\}[^0].\{8\}\|.\{24\}[^0].\{7\}\|.\{25\}[^0].\{6\}\|.\{26\}[^0].\{5\}\|.\{27\}[^0].\{4\}\|.\{28\}[^0].\{3\}\|.\{29\}[^0].\{2\}\|.\{30\}[^0].\|.\{31\}[^0]\)"\|""\)'
"SgxEpoch": "00000000000000010000000000000000"
[~]$ echo '"SgxEpoch": "00000000000000000000000000000000"' | grep '"SgxEpoch":\s*\("\([^0].\{31\}\|.[^0].\{30\}\|.\{2\}[^0].\{29\}\|.\{3\}[^0].\{28\}\|.\{4\}[^0].\{27\}\|.\{5\}[^0].\{26\}\|.\{6\}[^0].\{25\}\|.\{7\}[^0].\{24\}\|.\{8\}[^0].\{23\}\|.\{9\}[^0].\{22\}\|.\{10\}[^0].\{21\}\|.\{11\}[^0].\{20\}\|.\{12\}[^0].\{19\}\|.\{13\}[^0].\{18\}\|.\{14\}[^0].\{17\}\|.\{15\}[^0].\{16\}\|.\{16\}[^0].\{15\}\|.\{17\}[^0].\{14\}\|.\{18\}[^0].\{13\}\|.\{19\}[^0].\{12\}\|.\{20\}[^0].\{11\}\|.\{21\}[^0].\{10\}\|.\{22\}[^0].\{9\}\|.\{23\}[^0].\{8\}\|.\{24\}[^0].\{7\}\|.\{25\}[^0].\{6\}\|.\{26\}[^0].\{5\}\|.\{27\}[^0].\{4\}\|.\{28\}[^0].\{3\}\|.\{29\}[^0].\{2\}\|.\{30\}[^0].\|.\{31\}[^0]\)"\|""\)'
[~]$
的一堆替代品,我基本上说如果x号“除了换行符之外的任何字符”(通过|
),然后是一个.{x}
,然后是除了换行符之外的任何字符的x号码(通过0
)。在我看来,这个RegEx应该与以下示例相匹配,但它不会......而且我不明白为什么。
.{x}
这与它在bash脚本中的实现方式非常相似。在第一个输入fd<(curl ...)中,它以JSON格式从主机中提取所有BIOS设置。对于第二个fd<(echo ...),我以通用形式回显具有所需BIOS设置的变量。然后将两个输入到"SgxEpoch": "00000000000000010000000000000000"
"SgxEpoch": "00000000000000000000000001000000"
"SgxEpoch": "00000100000000000000000000000000"
以将两个输入按字母顺序排列为diff,漂亮的打印格式将JSON设置与| python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges'
分开,以便\n
仅显示用户的差异,perl将删除\ n个字符对于数组类型变量,因为我无法将diff作为“一个块”与--suppress-common-lines
之类的新行匹配。
.
注意:我几乎可以肯定我在堆栈溢出时发现了一个线程,其中有人审查了diff的源代码并发现它在逐行的基础上进行了比较但是找不到该线程的ATM。
注意2:我注意到当diff在[awilk00@nvdejb-dc-2p ~]$ SgxEpochRegEx='"SgxEpoch":\s*\("\([^0].\{31\}\|.[^0].\{30\}\|.\{2\}[^0].\{29\}\|.\{3\}[^0].\{28\}\|.\{4\}[^0].\{27\}\|.\{5\}[^0].\{26\}\|.\{6\}[^0].\{25\}\|.\{7\}[^0].\{24\}\|.\{8\}[^0].\{23\}\|.\{9\}[^0].\{22\}\|.\{10\}[^0].\{21\}\|.\{11\}[^0].\{20\}\|.\{12\}[^0].\{19\}\|.\{13\}[^0].\{18\}\|.\{14\}[^0].\{17\}\|.\{15\}[^0].\{16\}\|.\{16\}[^0].\{15\}\|.\{17\}[^0].\{14\}\|.\{18\}[^0].\{13\}\|.\{19\}[^0].\{12\}\|.\{20\}[^0].\{11\}\|.\{21\}[^0].\{10\}\|.\{22\}[^0].\{9\}\|.\{23\}[^0].\{8\}\|.\{24\}[^0].\{7\}\|.\{25\}[^0].\{6\}\|.\{26\}[^0].\{5\}\|.\{27\}[^0].\{4\}\|.\{28\}[^0].\{3\}\|.\{29\}[^0].\{2\}\|.\{30\}[^0].\|.\{31\}[^0]\)"\|""\),'
[awilk00@nvdejb-dc-2p ~]$ hostsettings='{"ServicePhone":"","SgxEpoch": "00000000000000000000000000000000","SgxEpochControl":"SgxEpochNoChange","DefaultBootOrder":["PcieSlotNic","EmbeddedFlexLOM","EmbeddedStorage","PcieSlotStorage","Usb","Cd","UefiShell","Floppy"]}'
[awilk00@nvdejb-dc-2p ~]$ desiredsettings='{"ServicePhone":"","SgxEpoch": "","SgxEpochControl":"SgxEpochNoChange","DefaultBootOrder":["Floppy","Cd","Usb","EmbeddedStorage","PcieSlotStorage","EmbeddedFlexLOM","PcieSlotNic","UefiShell"]}'
[awilk00@nvdejb-dc-2p ~]$ echo "${hostsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges'
{
"DefaultBootOrder": ["PcieSlotNic","EmbeddedFlexLOM","EmbeddedStorage","PcieSlotStorage","Usb","Cd","UefiShell","Floppy"],
"ServicePhone": "",
"SgxEpoch": "00000000000000000000000000000000",
"SgxEpochControl": "SgxEpochNoChange"
}
[awilk00@nvdejb-dc-2p ~]$ echo "${desiredsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges'
{
"DefaultBootOrder": ["Floppy","Cd","Usb","EmbeddedStorage","PcieSlotStorage","EmbeddedFlexLOM","PcieSlotNic","UefiShell"],
"ServicePhone": "",
"SgxEpoch": "",
"SgxEpochControl": "SgxEpochNoChange"
}
[awilk00@nvdejb-dc-2p ~]$ diff --report-identical-files --suppress-common-lines --side-by-side --ignore-matching-lines="${SgxEpochRegEx}" <(echo "${hostsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges') <(echo "${desiredsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges')
"DefaultBootOrder": ["PcieSlotNic","EmbeddedFlexLOM","Emb | "DefaultBootOrder": ["Floppy","Cd","Usb","EmbeddedStorage
"SgxEpoch": "00000000000000000000000000000000", | "SgxEpoch": "",
[awilk00@nvdejb-dc-2p ~]$
[awilk00@nvdejb-dc-2p ~]$
[awilk00@nvdejb-dc-2p ~]$ hostsettings='{"ServicePhone":"","SgxEpoch": "5FSQUWEED6XPC8PJ2CWZGQIS4WWKLKUI","SgxEpochControl":"SgxEpochNoChange","DefaultBootOrder":["PcieSlotNic","EmbeddedFlexLOM","EmbeddedStorage","PcieSlotStorage","Usb","Cd","UefiShell","Floppy"]}'
[awilk00@nvdejb-dc-2p ~]$ echo "${hostsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges'
{
"DefaultBootOrder": ["PcieSlotNic","EmbeddedFlexLOM","EmbeddedStorage","PcieSlotStorage","Usb","Cd","UefiShell","Floppy"],
"ServicePhone": "",
"SgxEpoch": "5FSQUWEED6XPC8PJ2CWZGQIS4WWKLKUI",
"SgxEpochControl": "SgxEpochNoChange"
}
[awilk00@nvdejb-dc-2p ~]$ echo "${desiredsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges'
{
"DefaultBootOrder": ["Floppy","Cd","Usb","EmbeddedStorage","PcieSlotStorage","EmbeddedFlexLOM","PcieSlotNic","UefiShell"],
"ServicePhone": "",
"SgxEpoch": "",
"SgxEpochControl": "SgxEpochNoChange"
}
[awilk00@nvdejb-dc-2p ~]$ diff --report-identical-files --suppress-common-lines --side-by-side --ignore-matching-lines="${SgxEpochRegEx}" <(echo "${hostsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges') <(echo "${desiredsettings}" | python -m json.tool | perl -00pe 's:\[.*?\]:($x=$&)=~s/\s//gs;$x:ges')
"DefaultBootOrder": ["PcieSlotNic","EmbeddedFlexLOM","Emb | "DefaultBootOrder": ["Floppy","Cd","Usb","EmbeddedStorage
[awilk00@nvdejb-dc-2p ~]$
正则表达式中存在匹配的行之前找到差异行时,diff不会删除与正则表达式匹配的两行并将它们显示为在前面的非正则表达式匹配线之后立即发现差异。希望我没有那个太糟糕的屠夫。例如:
--suppress-common-lines
由于数据的敏感性,我想确保我清楚地了解这个RegEx的工作原理。
我也非常感谢您可以围绕庞大的正则表达式提供任何语法验证,因为我不太了解它是如何工作的。
这里的问题是有人解释/验证正则表达式。我认为由于XY问题我最终会解释我的最终目标,但实际上我无法负担当前重新编写所有内容的时间。我对此持开放态度,但我有约会时间。
亚伦
答案 0 :(得分:1)
你的正则表达式看起来很好。也许问题是diff
的{{1}}选项(简写--ignore-matching-lines
),其效果与人们预期的不同。
-I
如何运作?让diff -I regex
和a
成为两个文件。
如果我没有阅读documentation,我希望以下两个命令是等效的:
b
这有两个方面是错误的:
diff -I regex a b
diff <(grep -v regex a) <(grep -v regex b)
始终考虑来自diff
和a
的对或行。如果两条线(来自b
的线和来自a
的线)都与正则表达式匹配,则忽略这样的一对。
即使该对中的两条线都匹配,也可能会忽略它们 。不仅两个行中的两行必须匹配,而且hunk中的所有行必须匹配!
第二点的示例(b
是-y
的简写):
--side-by-side
diff --suppress-common-lines -yI '1\|2' <(printf '1\n') <(printf '2\n')
第一个命令按预期工作,但第二个命令没有。而不是线对(diff --suppress-common-lines -yI '1\|2' <(printf '1\n1\n') <(printf '2\nX\n')
1 | 2
1 | X
,1
)差异尝试匹配来自大块的所有线((2
,1
),(1
,{ {1}}))。因为那个大块的一条线不匹配所以整个大块都印了。
2
我不完全确定您的典型输入和预期输出是什么。我猜到了:
您的文件X
可能包含第
一行
diff -I
您生成的文件original
将0行固定为类似的内容
"SgxEpoch": "00000000000000000000000000000000"
(需要帮助的地方)
您想比较两个文件generated
和"SgxEpoch": "5FSQUWEED6XPC8PJ2CWZGQIS4WWKLKUI"
,以确保您的第二步脚本做了正确的事情。为了使比较更容易,您只希望在original
的相应行为其中时看到差异
generated
或
original
有一个简单的解决方案。只需grep diff:
的输出"SgxEpoch": "00000000000000000000000000000000"