使用bash脚本删除两个其他字符串之间出现字符串的所有实例

时间:2017-06-27 15:37:51

标签: bash

我正在尝试编写一个bash脚本来编辑一个json文件来删除整个对象,但是我已经碰壁了。

这里是样本数据

[
   {
      "MapObject" : {
         "BoundingBox" : [ -1313.574, -1010.804, -1113.574, -810.804 ],
         "Caption" : "Ref46",
         "Comment" : "",
         "Position" : {
            "CPosition" : [ -1213.574, -910.804, 0, 0 ]
         },
         "Size" : {
            "CPosition" : [ 100, 100, 0, 0 ]
         },
         "Type" : "moReferencePointID"
      }
   },
   {
      "MapObject" : {
         "BoundingBox" : [ -1313.06, 495.39, -1113.06, 695.39 ],
         "Caption" : "Ref47",
         "Comment" : "",
         "Position" : {
            "CPosition" : [ -1213.06, 595.39, 0, 0 ]
         },
         "Size" : {
            "CPosition" : [ 100, 100, 0, 0 ]
         },
         "Type" : "moReferencePointID"
      }
   },
  {
      "MapObject" : {
         "BoundingBox" : [ -18070, 1180, -17870, 1380 ],
         "Caption" : "Path way84",
         "Comment" : "",
         "ExecutableMapObject" : {
            "BehaviourList" : [
               {
                  "Speed" : 200,
                  "Type" : "bcSpeed"
               },
               {
                  "AvoidanceSpeed" : 150,
                  "FailureAction" : 0,
                  "FailureRetries" : 60,
                  "FailureWait" : 10,
                  "PathMode" : 2,
                  "PerSegment" : 15,
                  "ReturnToStart" : 0,
                  "ScanAngle" : 0.06981317007977778,
                  "Type" : "bcObstacleAvoidance",
                  "Wait" : 10,
                  "WaitUnits" : 2
               },
               {
                  "BinarySensorStates" : 3,
                  "SensorSensitivityList" : [
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 65536,
                        "SpeedCapDistance" : 70,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 70
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 131072,
                        "SpeedCapDistance" : 70,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 70
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 262144,
                        "SpeedCapDistance" : 240,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 240
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 524288,
                        "SpeedCapDistance" : 240,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 240
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 1048576,
                        "SpeedCapDistance" : 240,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 240
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 2097152,
                        "SpeedCapDistance" : 280,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 280
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 4194304,
                        "SpeedCapDistance" : 320,
                        "SpeedCapEnabled" : true,
                        "StopDistance" : 320
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 8388608,
                        "SpeedCapDistance" : 0,
                        "SpeedCapEnabled" : false,
                        "StopDistance" : 0
                     },
                     {
                        "IgnoreMapData" : false,
                        "Mask" : 16777216,
                        "SpeedCapDistance" : 0,
                        "SpeedCapEnabled" : false,
                        "StopDistance" : 0
                     }
                  ],
                  "SpeedCap" : 30,
                  "Type" : "bcObstacleSensitivity2"
               }
            ],
            "EntryPoint" : {
               "CPosition" : [ -13450, 1290, 0, 0 ]
            },
            "ExitPoint" : {
               "CPosition" : [ -17970, 1280, 0, 0 ]
            },
            "RelocateOnExecute" : false,
            "Required" : false,
            "TwoWay" : false
         },
         "GoalSet" : [
            {
               "Path" : {
                  "PathType" : "pitLinear",
                  "Segments" : [
                     {
                        "Segment" : [ -13450, 1290, -17970, 1280 ]
                     }
                  ]
               }
            }
         ],
         "Position" : {
            "CPosition" : [ -17970, 1280, 0, 0 ]
         },
         "Size" : {
            "CPosition" : [ 0, 0, 0, 0 ]
         },
         "Type" : "moLinePathID"
      }
   },
   {
      "MapObject" : {
         "AttributeList" : [
            [ "Lock", "{} LabInt {}" ]
         ],
         "BoundingBox" : [ -12350, -500, -12150, -300 ],
         "Caption" : "QUEUE/LabInt",
         "Comment" : "",
         "ExecutableMapObject" : {
            "EntryPoint" : {
               "CPosition" : [ -12250, -400, 0, 0 ]
            },
            "ExitPoint" : {
               "CPosition" : [ -12250, -400, 0, 0 ]
            },
            "RelocateOnExecute" : false,
            "Required" : false,
            "TwoWay" : false
         },
         "Position" : {
            "CPosition" : [ -12250, -400, 0, 0 ]
         },
         "Size" : {
            "CPosition" : [ 100, 100, 0, 0 ]
         },
         "Type" : "moHotPointID"
      }
   },
]

每个对象都以

开头
    {

结束
    },

我想删除包含“Type”的所有对象及其数据:“moReferencePointID”和“moReferenceLineID”。

某些对象中有多个Type实例。

我一直在使用sed和awk使用我在网上找到的东西,并且不能完全使用它。任何帮助将不胜感激。

我发布了迄今为止我所做的事情,但它绝对无效......

3 个答案:

答案 0 :(得分:1)

正则表达式是解析结构化文本的错误答案;使用解析器是正确的答案。将整个文件读入内存也是错误的答案,但这就是解析器所做的事情,所以meh。

那就是说,错误的答案有时候是可以的:

  • 在琐碎的非生产数据集上的一次性脚本,您可以完全控制输入。例如,作为在两个系统之间迁移少量数据的一次性命令,您不想为此编写脚本。
  • 你所拥有的只是一个文本编辑器。
  • 您所处的实时服务器,并且不想安装或编写其他实用程序以执行简单的一次性任务。
  • 您正在使用只读服务器并且无法编写脚本
  • 各种灾难恢复/缓解情况。

了解何时不使用正则表达式以及如何使用更强大,更可靠的替代方案非常重要:但是当您真正需要它们时,了解如何使用正则表达式完成任务可以成为救星。< / p>

至少,这是一个有趣的教学练习,可以使用各种unix命令行实用程序来探索正则表达式和多行文本块处理。

<强> PHP:

php -r '$a=file_get_contents("data.json");file_put_contents("cleaned.json", preg_replace("/\{\s*\"MapObject(?:(?!MapObject)[\s\S])+\"Type\"\s*:\s*\"moReference(?:Point|Line)ID\"(?:(?!MapObject)[\s\S])+},?\s*/", "", $a));'

<强>的Perl:

$_=do{local $/;<>};只是让它在一行中读取文件。

perl -e '$_=do{local $/;<>};$_=~s/\{\s*\"MapObject(?:(?!MapObject)[\s\S])+\"Type\"\s*:\s*\"moReference(?:Point|Line)ID\"(?:(?!MapObject)[\s\S])+},?\s*//g;open($fh,">","cleaned.json");print $fh $_;' data.json

<强> awk中:

RS="<{EOF}>"只是让它作为一行读取文件。将字符串替换为绝对不会出现在数据集中的任何字符串。

awk -v RS="<{EOF}>" '{gsub(/\{[\r\n\t ]*\"MapObject/, "\x1E&");print $0}' < data.json > data1.json
awk -v RS="<{EOF}>" '{gsub(/\x1E[^\x1E]*\"Type\"[\t ]*:[\t ]*\"moReference(Point|Line)ID\"[^\x1E]*},[\r\n\t ]*|\x1E/, "");print $0}' < data1.json > cleaned.json

<强>桑达:

-e 1h;2,$H;$!d;g只是让它在一行中读取文件。

 sed -e '1h;2,$H;$!d;g' -E -e 's/\{\s*\"MapObject/\x1E\0/g' < data.json > data2.json
 sed -e '1h;2,$H;$!d;g' -E -e 's/\x1E|\{[^\x1E]*\"Type\"\s*:\s*\"moReference(Point|Line)ID\"[^\x1E]*},\s*//g' < data2.json > cleaned.json

OSX Sed

echo 'Just use vi' | sed -e '' && vi data.json

在上面的所有情况中,我已经完成了将整个文件作为单个字符串读取所花费的一切,然后全局替换正则表达式与空字符串匹配的内容。

这些解决方案依赖于这样一个事实:每个对象都以可识别的开放模式\{\s*"MapObject"\s*:\s*\{开头,在每个对象的开头只出现一次。

PHP和Perl可以直接使用它,使用负前瞻断言。

然而,Sed和Awk并不支持环顾四周的断言,也不支持非贪婪的匹配。所以,我需要一个单宽度标记,所以我必须在多个传递中执行:一个将一些标记字符附加到开始模式(我选择了0x1E,ascii控制代码为&#34;记录分隔符&#34;) ;和一个做实际更换。

如果您的代码可能包含任意字节值,而不是可读文本,那么您将需要另外两次传递,首先将所有0x1E替换为不会出现在文本中的字符串,然后将该字符串替换为结束。

Awk似乎也不支持(在我的OSX机器上)空格的转义,所以我使用了字符组。

正则表达式可以描述为:

\{\s*"MapObject"          The opening pattern, starting an object.
(?:(?!MapObject)[\s\S])+  Some characters, not the opening pattern.
\"Type\"                  Literal quoted string "Type".
\s*:\s*                   Whitespace wrapped literal colon ':'.
\"moReference             Literal doublequote and start of string.
(?:                       Non-capturing group of...
  Point                   ...literal string 'Point'...
  |                       ...or...
  Line                    ...literal string 'Line'.
)                         Finish that logical grouping.
ID\"                      End of literal string and doublequote.
(?:(?!MapObject)[\s\S])+  More characters, not the opening pattern.
}                         Closing brace.
,?                        Optional comma.
\s*                       Optional trailing whitespace.

你可以在这里看到这个可怕的野兽,可以看到使用包含多个类型行的对象:https://regex101.com/r/XGULr5/4

答案 1 :(得分:0)

在这种情况下,

jq是你的朋友。它的食谱has an example应该适应这一点。

答案 2 :(得分:0)

{
if ($0 ~ /{/) {
    strt=1;cnt++
    }
if (strt=1) {
            print cnt
            bits[cnt]=bits[cnt]"\n"$0
            if ( $0 ~ /Type/ ) {
                                    typ[cnt]=$0
            }
        }
if ( $0 ~ /}/ ) {
    strt=0
    }
}
END{
for ( i=1;i<=cnt;i++ ) {
    if ( typ[i] ~ /NotGood/ || typ[i] ~ /Bad/ ) {

    }
else {
    printf bits[i]
    }
}
}

上面的awk代码应该可以工作(使用awk -f codefile datafile运行)。基本上我们检查“{”的每一行(模式匹配),然后开始将每一行写入一个数组(位),直到“}”模式匹配。除此之外,还会编写一个附加数组(典型值)来跟踪模式匹配“类型”的行。在代码的最后,位数组循环,引用typ。如果typ包含“NotGood”,则忽略位数,否则打印。

作为一个班轮,解决方案将是:

awk '{ if ($0 ~ /{/) { strt=1;cnt++ } if (strt=1) { pnt;bits[cnt]=bits[cnt]"\n"$0;if ( $0 ~ /Type/ ) { typ[cnt]=$0 } } if ( $0 ~ /}/ ) { strt=0 } } END { for ( i=1;i<=cnt;i++ ) { if ( typ[i] ~ /NotGood/ || typ[i] ~ /Bad/ ) { } else { printf bits[i] } } }' filename