【问题标题】:sed delete unmatched lines between two lines with bash variablesed 用 bash 变量删除两行之间不匹配的行
【发布时间】:2016-06-29 10:03:04
【问题描述】:

我需要帮助来理解 sed、bash 和 while 循环的一个奇怪问题。

我的数据如下所示:

-文件 1- CSV account,hostnames,status,ipaddress,port,user,pass

-文件 2- XML - 这是一个帐户下的两个条目的示例记录集

<accountname="account">

<cname="fqdn or simple name goes here">
<field="hostname">ahostname or ipv4 goes here</field>
<protocol>aprotocol</protocol>
<field="port">aportnumber</field>
<field="username">ausername</field>
<field="password">apassword</field>
</cname>

<cname="fqdn or simple name goes here">
<field="hostname">ahostname or ipv4 goes here</field>
<protocol>aprotocol</protocol>
<field="port">aportnumber</field>
<field="username">ausername</field>
<field="password">apassword</field>
</cname>

</accountname>

到目前为止,我可以在从 File1 到 File2 的各个帐户持有人之间添加记录。但是,如果我需要删除不再存在的记录,它不会有效地工作,因为它会擦除来自不同帐户的其他记录,即它不会在匹配的帐户名之间删除。

我在 bash 程序中使用 while 循环从文件 1 导入文件 2:

-Bash Program excerpts-
//Read File in to F//
cat File 2 | while read F
do

//extract fields from F into variables
_vmname="$(echo $F |grep 'cname'| sed 's/<cname="//g' |sed 's/.\{2\}$//g')"
_account="$(echo $F | grep 'accountname' | sed 's/accountname="//g' |sed 's/.\{2\}$//g')"

  //  I then compare my File1 and look for stale records that are still in File2

        if grep "$_vmname" File1 ;then
                continue
        else
// if not matched, delete between the respective accountname

sed -i '/'"$_account"'/,/<\/accountname>/ {/'"$_vmname"'/,/<\/cname>/d}' File2

如果我手动声明 _vmname 和 _account 并运行

sed -i '/'"$_account"'/,/<\/accountname>/ {/'"$_vmname"'/,/<\/cname>/d}' File2

它从 File2 中删除过时的记录。当我让我的 bash 脚本运行时,它没有。

我认为我有三个问题:

  1. 在循环中读取 _vmname 和 _account name 的变量会导致多次读取。任何更好的方法都值得赞赏。
  2. 我认为用于匹配这两种模式然后删除的 sed 语句在 while 循环中不会像我想要的那样工作。
  3. 我的思维链可能有逻辑问题。

任何指针,请不要使用 awk、perl、lxml 或 python。

谢谢!

【问题讨论】:

  • 你没有尝试插入一些echo 行来跟踪循环内一些变量的值吗?您是否尝试过手动运行擦除sed 命令并检查它是否有效?
  • 股票建议:不要使用像 sed 这样的面向行的工具来操作 XML 数据。请改用xsltprocxmlstarlet 等支持XML 的工具。
  • 是的,在循环外运行 sed 语句可以正常工作,并且使用 echo 进行跟踪表明我的 _vmname 和 _account 字段正在被读取并为每条记录解析三次。
  • 尝试将 while 循环更改为重定向而不是管道,while read F; do ... done &lt; File2。另外,您在条件中的 grep 是指grep -q 吗?也许你想要这样的东西:grep -q "$v_name" File1 &amp;&amp; continue
  • 您的 XML 不是 XML。

标签: bash sed


【解决方案1】:

请不要 awk

我很感激你想让事情保持简单,我想 awk 似乎比你正在做的更复杂。但我想指出,到目前为止,您在文件中 每行 有 3 个 grep 和 4 个 sed 调用,用于处理 另一个 文件 N次,每行一次。那是 O(mn) 使用地球上最慢的方法来读取文件(while 循环)。而且它不起作用。

我的思维链可能有逻辑问题。

恐怕我们必须允许这种可能性!

正确的建议是使用 XML 解析器处理 XML,因为 XML 不是常规语言,因此无法使用正则表达式进行解析。这正是您真正需要的,因为您的程序处理整个 XML 文档。您不只是提取位并依赖于偶然的格式化工件;您想添加不存在的记录并删除“不再存在”的记录。显然,您需要保留 XML 文档中的信息,否则您只需从 CSV 生成它。解析器会用勺子喂给你。

第二好的建议是使用 awk。我想您可以尝试以下方法:

  1. 处理 CSV 并生成要插入的 XML。
  2. 在 awk 中,首先将新输入的 XML 读入以 cname 为键的数组,然后处理 XML 目标一次。对于每个 CNAME,请查阅您的数组;如果找到匹配项,请插入预先构建的 XML 替换(或相应地修改“段落”)。
  3. 我不确定删除标准是什么,所以我不知道它是否可以在与步骤 #2 相同的过程中完成。如果没有,以某种方式提取显着信息。也许从两个文件中的每一个中打印一个键列表,并使用 comm(1) 生成一个要删除的列表。然后,与第 2 步类似,读入该列表,并再次处理 XML 文件。将您删除的任何内容写入 stderr,以便您可以跟踪丢失的内容,从哪些行开始。

任何指针

每当您发现自己为 N 个输入处理同一个文件 N 次时,您就知道自己遇到了麻烦。两个输入中的一个总是较小,并且可以将其放入某种数组中。 cat file | while read 是另一个警告信号,告诉您使用 awk 或十几个可以理解文本行的明显实用程序中的任何一个。

您两周前在 SO 上发布了您的问题。我怀疑没有人回答它,因为你警告过他们:先发制人地说,实际上,不要告诉我使用好的工具。我只是在这里建议你脱下那件紧身衣后会更舒服。在这种情况下,更好的工具是唯一正确的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-01
    • 1970-01-01
    • 2021-05-26
    • 1970-01-01
    相关资源
    最近更新 更多