【问题标题】:Check if a string in one file exists in another in unix检查一个文件中的字符串是否存在于unix中的另一个文件中
【发布时间】:2014-12-26 01:43:17
【问题描述】:

我有一个包含版本名称和版本号的文件。第一个文件的内容看起来像 -

File1-

<Line contains the name of product1>
package_name0_9_8 >= 1.2.3x-4.5.6
package_name0_9_8-32bit >= 3.6.1g-3.5.1
package_name0_9_8-xx >= 6.3.2v-3.0.4
<Line contains the name of product2>
anotherpackage_name0_9_8 >= 3.5.6u-3.6.5

还有,

File2.xml-

<package name="package_name0_9_8" version="1.2.3x-4.4.4"/>
<package name="package_name0_9_8-32bit" version="3.6.1g-3.4.0"/>
.
.

有没有办法用 File2 的 package_name 检查 File1 中存在的 package_name 的存在,并检查 File1 中的 package_name 的对应版本是否与 File2 的 package_name 的对应版本?

坦率地说,我在连接“grep”和“awk”命令以及此处使用的选项方面非常薄弱。请帮忙。

【问题讨论】:

  • 您是否对 Python 解决方案感兴趣?
  • @user2962794:是的,非常欢迎。一个 Python 解决方案就可以了。
  • @shellter:谢谢。是的,那条线没有意义。我想,我会这样输出。

标签: unix awk sed grep


【解决方案1】:

for a in $(sed -n '/&gt;=/p' File1.txt | grep -o '^[^ ]*'); do for b in $(sed -n "/^$a /{s/.*&gt;=\(.*\)$/\1/p}" File1.txt); do ((! $(grep -c "$a.*$b" File2.txt))) &amp;&amp; (echo "$a $b" &gt;&gt; missing_pkgs.txt); done; done;

这是一个快速的衬里 - 你可以把它打印出来更漂亮

这种工作方式是嵌套的 for 循环,它将两个部分分别抓取到变量中(如果需要,您可以使用 read 并将它们放在一个循环中),然后只需使用 grep 计算第二个文件中的出现次数,并且无论何时计数为零,它将反转使测试(())变为真的值并将丢失的包回显到文件missing_pkgs.txt

这是另一个快速的单行器,它做同样的事情,除了一个循环和通过读取加载的变量更有效

while read each; do read a b &lt; &lt;(echo $each) &amp;&amp; ((! $(grep -c "$a.*$b" File2.txt))) &amp;&amp; (echo "$a $b" &gt;&gt; missing_pkgs.txt); done &lt; &lt;(awk '/&gt;=/{ print $1" "$3 }' File1.txt)

更简化:

while read a b; do ((! $(grep -c "$a.*$b" File2.txt))) &amp;&amp; (echo "$a $b" &gt;&gt; missing_pkgs.txt); done &lt; &lt;(awk '/&gt;=/{ print $1" "$3 }' File1.txt)

【讨论】:

  • 谢谢!使用您的想法,我尝试使用sed -n "/&gt;=/p" File1 | grep -o "^[^ ]*" &gt; package_namessed -n "/^/{s/.*&gt;= \(.*\)/\\1/p}" File1 &gt; package_versions。我刚刚将这些行放入 shell 脚本(只是为了使其更简单和透明)并运行脚本。现在,相同的 shell 脚本应该检查 package_names 中的 line1File2,然后检查 package_versions 中的 line1File2。请帮忙。我对 shell 脚本的想法也少得多。
  • 我会选择第二个版本,因为它更简单,如果需要你可以进一步简化为:while read a b;做 ((!$(grep -c "$a.*$b" File2.txt))) && (echo "$a $b" >> missing_pkgs.txt);完成 =/{ print $1" "$3 }' File1.txt)
  • 现在明白了。而且,如何将$1$3 存储到最后一部分使用的两个单独变量&lt;(awk '/&gt;=/{ print $1" "$3 }' File1.txt) 中,以便在后面的部分中更好地输出格式?
  • while 读 a b;这样做 - 如果您在完成后查看脚本的结尾,则进程替换的输出
  • 如果您想更改当前输出格式,您可以修改部分:echo "$a $b" >> 改为您需要的任何内容。
【解决方案2】:
sed -n 's².*²s#<package name="\\(&"/>#\\1 Present#p²;s/ *>= */\\)" *version="/p' File1 > /tmp/File1.sed
sed -n -f /tmp/File1.sed File2
rm /tmp/File1.sed 
  • 不像 awk 那样在指令上可以做,但做的工作(posix 版本所以--posix 在 GNU sed 上
  • 您可以更改输出消息,即\\1 Present 文本,其中\\1 将是包名称(只需少量修改,也可以使用版本)

【讨论】:

  • 或者您可以将第一个命令的输出发送到第二个:sed -n 'stuff' File1 | sed -n -f - File2
  • @NeronLeVelu:我可以知道第一行的方形符号是做什么的吗?我不熟悉那个符号。另外,能否请您详细说明第二个要点?
  • #² 一样在这里用作传统s/// 的模式分隔符,而不是模式本身中使用的/。 sed 将s 之后的第一个字符作为分隔符。因为它用于 2 个不同的 sed(第一个创建第二个)我使用 2 个不同的分隔符。
  • @aragaer 就在 bash (linux) 中,但我在这里使用 AIX KSH,所以| ... - 在这种情况下失败了。无论如何都是好点
  • 再次抱歉!我仍然不太清楚。那个符号可以换吗?另外,请评论\\1 Present
【解决方案3】:

看起来您已经得到了一个更短的解决方案,其格式更接近您想要的。但是,既然我问过 Python 解决方案是否可行,而您说可以,请查看此处的代码:

http://pastebin.com/F5LYrmea

(我没有调试过它,但它似乎至少比你的示例文件更有效。我将代码发布到公共领域。CC-BY-SA 不是软件许可证,根据 CC 的制造商的说法;所以,这就是我没有在此处发布它的原因,因为在此处发布它会赋予它该许可证。另外,您可以在提供的链接中获得特定于 Python 的语法突出显示。)

基本上,这是很多复杂的文本解析。没有太多的算法可以解释。它获取两个文件的内容,删除包、它们的版本和操作数(将所有这些放在字典中以供以后使用),并循环通过另一个文件的行并比较版本;然后它会告诉你哪些匹配,哪些不匹配。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 2011-02-12
    • 1970-01-01
    • 2014-01-20
    • 2021-08-18
    • 2012-12-07
    相关资源
    最近更新 更多