删除可能不同行上的2个分隔符之间的字符串

时间:2015-02-06 01:49:55

标签: regex bash awk sed

背景:我有一个配置文件,用于存储此格式的变体值:

(以下是使用虚构数据的示例)

'names': { "john", "jeff", "stewie", "amy", "emily" }

一些格式详情:

  • 'names'和:
  • 之间永远不会有空格
  • “{”和“john”
  • 之间可能存在或者可能不是空格
  • 列表成员之间总是有空格(“john”总是 在“jeff”之前有一个“,”
  • “emily”和“}”
  • 之间可能存在或者可能不是空格
  • 此列表中的元素可以按行而不是按行描述 空间。例如,这也是可以接受的:

    'names': { "john",
               "jeff",
               "stewie",
               "amy",
               "emily"
             }
    

这就是:

    'names': { "john", "jeff", "stewie",
               "amy", "emily" }

我正在尝试创建的功能:我想从名为“names”的列表中删除“amy”。

我一直在尝试使用sed创建此行为,但我愿意使用bash,awk,cut或其中的一些组合。

如果列表中的元素在一行上,这很容易:

/bin/sed -i "/names/ s/ ${element}//" $f

(其中$element包含"amy"$f包含我正在编辑的文件

但多线的可能性让我感到高兴。

思想?

3 个答案:

答案 0 :(得分:2)

让我们考虑包含所有三种情况的输入文件:

$ cat file
'names': { "john", "jeff", "stewie", "amy", "emily" }
'names': { "john",
           "jeff",
           "stewie",
           "amy",
           "emily"
         }
'names': { "john", "jeff", "stewie",
               "amy", "emily" }

现在,让我们应用此sed命令删除amy

$ sed '/names/{:a;/}/!{N;b a}; s/"amy",[[:space:]]*//}' file
'names': { "john", "jeff", "stewie", "emily" }
'names': { "john",
           "jeff",
           "stewie",
           "emily"
         }
'names': { "john", "jeff", "stewie",
               "emily" }

如何运作

  • /names/

    任何时候一行包含names,我们就会开始执行命令。其他行未更改。

  • :a; /}/! {N;b a}

    一旦我们的行包含names,我们会读到其他行,直到我们得到一个包含右括号的行。即使它分布在多行上,也会立即获得完整的names分配。

    更详细地说,:a是一个标签。 /}/!是一个条件。如果该行不包含},则执行语句N; b aN读取下一行并将其添加到模式空间。 b a跳转(分支)回标签a。因此,这种情况一直持续到从names}的完整分配都在模式空间中。

  • s/"amy",[[:space:]]*//}

    在sed的模式空间中完成names分配后,我们会查找"amy",以及后面的任何空格,我们将其删除。

即使她是列表中的最后一个,也要删除amy

上述解决方案假定逗号后跟名称amy。但是,假设amy可能是列表中的姓氏,如下文所示:

$ cat file
'names': { "john", "jeff", "stewie", "emily", "amy" }
'names': { "john",
           "jeff",
           "stewie",
           "emily",
           "amy"
         }
'names': { "john", "jeff", "stewie",
               "emily", "amy"}

要处理这种情况,我们需要添加一个替代命令:

$ sed '/names/{:a;/}/!{N;b a}; s/"amy",[[:space:]]*//; s/,[[:space:]]*"amy"//}' file
'names': { "john", "jeff", "stewie", "emily" }
'names': { "john",
           "jeff",
           "stewie",
           "emily"
         }
'names': { "john", "jeff", "stewie",
               "emily"}

答案 1 :(得分:0)

使用sed如下:

sed  -r ':loop;$!{N;b loop};s/(.names.: ?\{[^}]*)"amy",? *([^}]*\})/\1\2/g' my-file

答案 2 :(得分:0)

为什么不直接使用bash字符串处理例程:

http://tldp.org/LDP/abs/html/string-manipulation.html

stringZ=abcABC123ABCabc
echo ${stringZ/abc/xyz}

result = bcABC123ABCxyz

在你的情况下

export stringZ="\'names\': \{ \"john\", \"jeff\", \"stewie\", \"amy\", \"emily\" }"

echo ${stringZ/\"amy\",/} 

返回'姓名':{“john”,“jeff”,“stewie”,“emily”}