我想使用 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版本
相同的脚本,除了重写bash
为sed
#!/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