即使跨越多行,也替换括号之间的任何内容

即使跨越多行,也替换括号之间的任何内容

我想使用 bash 或 shell 脚本并替换任何事物两个括号之间有一个空格。两个括号之间的文本可以是多行,例如:

myFunction (line0

line1

line2

line3

line4) 

我想转换为:

myFunction ( )

答案1

获取bash@Serg 的答案并将其转换为使用 bash 内置函数,而不是每行 2 或 3 个进程。流程很便宜,但并非免费!

#!/bin/bash
# Use shell builtins, read, true, false, printf
flag=false
while IFS= read -r line
do
    case "$line" in
    (*"("*) flag=true ;;
    esac

    if $flag
    then
        line=${line//line/newline} 
    fi

    printf "%s\n" "$line"

    case "$line" in
    (*")"*) flag=false ;;
    esac

done < "$1"

答案2

AWK

{}AWK 允许在一定范围的条件下执行代码块。在本例中,我们希望gsub()在从包含(到包含 的行范围内执行每一行)

$ awk '$0~/[(]/,$0~/[)]/{gsub(/line/,"newline")};1' input.txt                                                     
another line
something else

myFunction (newline0

newline1

whatever

newline2

newline3

newline4)

some other line

Python(原始答案)

这是一个完成这项工作的快速 python 脚本:

#!/usr/bin/env python3
from __future__ import print_function
import sys

with open(sys.argv[1]) as fp:
    flag = None
    for line in fp:
        clean_line = line.strip()
        if "(" in clean_line: flag = True
        if flag:
           clean_line = clean_line.replace("line","newline")
        print(clean_line) 
        if ")" in clean_line: flag = False

测试运行:

$ cat input.txt                                                                                                          
another line
something else

myFunction (line0

line1

lilne2

line3

line4)

some other line
$ ./edit_function_args.py input.txt                                                                                      
another line
something else

myFunction (newline0

newline1

newline2

newline3

line4)

some other line

bash版本

相同的脚本,除了重写bashsed

#!/bin/bash
flag=false
while IFS= read -r line
do

    if grep -q '('  <<< "$line"
    then
        flag=true 
    fi


    if $flag
    then
        line=$(sed 's/line/newline/'   <<< "$line") 
    fi

    printf "%s\n" "$line"


    if grep -q ')'  <<< "$line"
    then
        flag=false     
    fi

done < "$1"

答案3

如果perl解决方案没问题并且文件足够小可以作为一个整体进行处理:

$ perl -0777 -pe 's/\([^)]+\)/$&=~s|line|newline|gr/ge' ip.txt    
myFunction (newline0

newline1

newline2

newline3

newline4) 
  • -0777吞掉整个输入文件
  • \([^)]+\)要匹配的模式 -(后跟非)字符并以结尾)
  • $&=~s|line|newline|gr此处使用引用匹配的模式$&,并完成所需的替换(行到换行符)。请注意r将结果作为替换字符串返回的标志
  • e标志允许使用表达式而不是字符串
  • 用于perl -i -0777 -pe就地编辑

答案4

使用awk
awk '
  function mysub(str) {
    if (str) gsub(/line/, "newline", str); return str
  }
  BEGIN {
    OFS=FS="("
  }
  NF>1 {
    if (FS=="(") {
      print $1,mysub($2); OFS=FS=")"
    } else {
      print mysub($1),$2; OFS=FS="("
    }
    next
  }
  {
    print FS=="(" ? $0 : mysub($0)
  }' /path/to/input

自定义函数mysub是您在括号之间进行所需替换的地方。假设括号不是嵌套的。

怎么运行的:

有两种状态,括号内和括号外。

  • 在外部(起始状态),输入和输出分隔符设置为左括号 ( OFS=FS="(")。
  • 一旦遇到一行包含多个由输入分隔符 ( NF>1) 分隔的字段并且...
    • ...您当前处于外部模式(FS=="("),字段分隔符之前和之后的所有内容都被输出(输出分隔符位于中间),但后者经过替换功能(mysub($2)),然后通过更改输入来翻转模式和输出分隔符 ( OFS=FS=")"),
    • ...否则(else),您处于内部模式,并且输出字段分隔符之前和之后的所有内容,但这次前者经过替换函数(mysub($1)),并且模式也会在此处翻转。
  • 在所有其他行上,如果在 ( ) 之外,则整行输出不变,FS=="("否则作为一个整体通过替换函数 ( mysub($0))。
压缩成一行:
awk 'function m(s){gsub(/line/,"newline",s);return s}BEGIN{OFS=FS="("}NF>1{if(FS=="("){print $1,m($2);OFS=FS=")"}else{print m($1),$2;OFS=FS="("}next}{print FS=="("?$0:m($0)}' /path/to/input
我的更棘手的测试数据(这里的一些单行解决方案将失败):
line96
line97 myFunction (line0

line1

line2

line3

line4) line98
line99
其输出:
line96
line97 myFunction (newline0

newline1

newline2

newline3

newline4) line98
line99
删除括号之间的所有内容的变体(除了第一个和最后一个换行符):
awk '
  BEGIN {
    OFS=FS="("
  }
  NF>1 {
    if (FS=="(") {
      print $1,""; OFS=FS=")"
    } else {
      print "",$2; OFS=FS="("
    }
    next
  }
  FS=="("' /path/to/input
此输出:
line96
line97 myFunction (
) line98
line99

相关内容