搜索、插入、移动和插入

搜索、插入、移动和插入

我想搜索文件中的每条记录(记录由空行定义)以查找模式NAME#AAAA。如果匹配,则#在记录AGE行前面插入 ,并将该行移动到段落顶部。然后AGE NIL在末尾插入该行:

输入文件:

NAME#AAAA
STD 1
SEC A
AGE 5

NAME#BBBB
STD 2
SEC B
AGE 6


NAME#CCCC
STD 3
SEC C
AGE 7

NAME#AAAA
STD 4
AGE 9


NAME#AAAA
STD 7
SEC A
AGE 12

预期产出

#AGE 5
NAME#AAAA
STD 1
SEC A
AGE NIL

NAME#BBBB
STD 2
SEC B
AGE 6

NAME#CCCC
STD 3
SEC C
AGE 7

#AGE 9
NAME#AAAA
STD 4
AGE NIL

#AGE 12
NAME#AAAA
STD 7
SEC A
AGE NIL

另外,我需要它的逆。只是为了恢复所做的更改。请注意,我是在 AIX 机器上执行所有这些操作的。

答案1

ex这是POSIX 指定的文件编辑工具的完美用例。

vi(顺便说一句,如果您曾经使用过,您可能会很熟悉,ex因为您输入的vi以冒号开头的所有内容:都是ex命令。 ex是 的前身vi。)

printf %s\\n 'g/NAME#AAAA/ /AGE/t- | s/^/#/ | /AGE/s/.*/AGE NIL/' x | ex input.txt

如果你想在实际保存文件之前进行测试,请将x管道符号之前的最后一个更改为%p,修改后的文件将不会被保存,但修改后的版本将打印到stdout.所以这是测试命令:

printf %s\\n 'g/NAME#AAAA/ /AGE/t- | s/^/#/ | /AGE/s/.*/AGE NIL/' %p | ex input.txt

解释:

printf %s\\n提供了一种简单的方法来输入多个命令,并ex在每个命令后添加一个换行符。

g/regex/是全局命令;它在与给定正则表达式匹配的每一行上运行后面的命令(直到下一个换行符)。

/AGE/t-将与模式匹配的下一行复制/AGE/到当前行(即该行)之前的位置NAME#AAAA。它还将光标移动到该行的新副本(以便现在成为“当前行”)。

|是 中的命令分隔符ex

s/^/#/在复制的AGE行前添加主题标签。 (或者井号,具体取决于您的方言。);)

下一个命令实际上有两个部分:/AGE/是地址,它使该命令在包含该模式的下一行上运行,并s/.*/AGE NIL/用 替换该行的任何内容AGE NIL

x保存对文件的更改并退出。


撤销更改

要撤销更改,我将执行以下操作:

printf %s\\n 'g/NAME#AAAA/ ?^#AGE? m /^AGE/ | s/^#// | -d' %p | ex input.txt

然后,当更改得到验证时,实际保存更改:

printf %s\\n 'g/NAME#AAAA/ ?^#AGE? m /^AGE/ | s/^#// | -d' x | ex input.txt

解释:

与以前一样的全局命令。

取出 NAME 行之前的以 开头的行#AGE,将其移到以 开头的下一行之后AGE

删除前导#.

删除紧邻的前一行-d(即 NIL 年龄行)。

打印或保存更改。

答案2

perl -pe 'BEGIN{$/=""} 
          s/^(NAME#AAAA.*\n)(AGE.*?)(\n+)$/#$2\n$1AGE NIL$3/s' ex1

非常简短的解释:

For all the registers in input                 |  perl -p
   separator= one or more empty lines          |     BEGIN{$/=""}
do:
  | substitute                                 |     s/
  |   ^(NAME AAAA.*\n)(AGE.*?)(\n+)$           |       regex /
  |    1              2       3                | 
  | by                                         |      /subst. string including
  |   # $2 \n  $1   AGE NIL   $3               |       capture groups/
  |                                            |
  | and print                                  |  ...from option -p

更新:

是否可以用变量代替 NAME#AAAA ?

perl -pe '
    BEGIN{
       $/=""; 
       $f=shift;  }
    s/^(NAME#$f.*\n)(AGE.*?)(\n+)$/#$2\n$1AGE NIL$3/s' AAAA  ex1

在此版本中我们必须提供一个图案参数(例如:“AAAA”):

  • 第 4 行:从命令行获取第一个参数(“AAAA”)并将其存储在 $f 中
  • 第 5 行:在替换模式中展开 $f。

相关内容