使用 sed / awk 更改两种模式之间的单词

使用 sed / awk 更改两种模式之间的单词

我正在编写应该处理一些文本的 shell 脚本,我得到了这样的文本:

read build { file1 file2 file3 }
check build { file2 file3 file4 }
read build { file4 file5 file6 }

我想在所有文件之前添加一些文本 - 这意味着单词,包含在“读取构建”行的括号之间,您认为实现这一目标的最佳想法是什么?结果应该如下所示:

read build { MY_ADDED_WORDfile1 MY_ADDED_WORDfile2 MY_ADDED_WORDfile3 }
check build { file2 file3 file4 }
read build { MY_ADDED_WORDfile4 MY_ADDED_WORDfile5 MY_ADDED_WORDfile6 }

我正在尝试 grep 该行,接下来将其解析为数组并将此“文件”字符串与我要添加的单词连接起来,但我认为这不是一个“智能”解决方案。感谢您的帮助。

输入文件如下所示:

set build { file1 file2 file3 file4 }
check $build

read build -new -f $build
read build -new -f { fileA fileB fileC fileD }

set build {file5 file6 file7 }

read build -old -f $build
read build -old -f { fileX fileZ fileD }

check_that_building

输出应该如下所示:

set build { file1 file2 file3 file4 }
check $build

read build -new -f $build
read build -new -f { MY_ADDED_WORDfileA MY_ADDED_WORDfileB MY_ADDED_WORDfileC MY_ADDED_WORDfileD }

set build {file5 file6 file7 }

read build -old -f $build
read build -old -f { MY_ADDED_WORDfileX MY_ADDED_WORDfileZ MY_ADDED_WORDfileD }

check_that_building

左括号前总是有一个空格,但也可能出现左括号后没有空格的情况,右括号前可以有空格,但并不总是如此。可能的情况:

read build -old -f { fileX fileZ fileD }
read build -old -f {fileX fileZ fileD }
read build -old -f { fileX fileZ fileD}
read build -old -f {fileX fileZ fileD}

答案1

sed 如果不假设至少有一个已知永远不会出现在输入中的字符,我无法立即弄清楚如何执行此操作。我假设它#永远不会出现在输入中(或您添加的单词中)。这似乎有效:

sed '/read build/ {
        s/{/{ /
        : fruit
        s/\({.*\) \([^}# ][^ ]*\)/\1#MY_WORD\2/
        t fruit
        s/#/ /g
        s/{ /{/
}'

在包含read build 它的行上,首先在 后插入一个空格{。然后它会搜索 a 之后{ 且紧邻单词(可能是文件名)之前的空格。它将空格替换为#,插入您的单词,然后返回并查找更多内容。 (fruit是任意循环标签。) 一旦找到所有字符,它将所有#字符转回空格,并删除它插入的空格(在 后面{)。

#除了关于输入中未出现的信息之外,还假设

  • }是每行的最后一个非空白字符read build,并且
  • 空白只是空格;没有选项卡。

awk

awk '/read build/ {
        in_braces=0
        for (i = 1; i <= NF; i++) {
                if ($i == "{") in_braces=1
                else if (substr($i,1,1) == "{") {
                        $i = "{MYWORD" substr($i,2)
                        in_braces=1
                }
                else if ($i == "}") in_braces=0
                else if (in_braces) $i = "MY_WORD" $i
        }
      }
      { print }'

对于每一read build行,它循环遍历该行中的所有单词(字段)。它使用状态变量 ( in_braces) 来跟踪它是否在 a{和 a之间};如果是,它会修改每个单词以您添加的单词开头。请注意,它必须处理两种略有不同的情况:

  • 如果一句话 {,设置标志以开始修改所有后续单词,并且
  • 如果一句话开始于 {,它实际上是形式的复合 ,所以修改{fileX{、添加的单词和fileX文件名。并且还设置标志来修改所有后续单词。

虽然这允许制表符作为单词分隔符,但它的缺点是将空格折叠为单个空格。例如,输入

read build    {    file1    file2    file3    }

会产生输出

read build { MY_WORDfile1 MY_WORDfile2 MY_WORDfile3 }

此外,这假设

  • the{位于单词的开头(即前面有空格),并且
  • 要么}是每行的最后一个非空白字符read build,要么是一个单独的单词(即前后都有空格)

它允许多组牙套;例如,

read build { file1 file2 file3 } text to be left alone { file4 file5 file6 }

相关内容