regex在sed中保留当前行但删除下一行

rqqzpn5f  于 2023-08-08  发布在  其他
关注(0)|答案(8)|浏览(82)

以下是示例数据:

ServerA
Value1 fh824rfz
Plan CustomA
ServerB
Value3 9fgjzxlo
Plan CustomD
ServerC
Value10 339fgh0l
Plan CustomE

字符串
下面是vscode中的正则表达式:

(Value[0-9]{1,2} [0-9a-z]{8}\n)(.*)


预期的输出:

ServerA
Value1 fh824rfz
ServerB
Value3 9fgjzxlo
ServerC
Value10 339fgh0l


但是我尝试在sed中使用这样的正则表达式,但它们不起作用:

-E 's|(Value[0-9]{1,2} [0-9a-z]{8}\n)(.*)\n|\1|g'
-re 's|(Value[0-9]{1,2} [0-9a-z]{8}\n)(.*)\n|\1|g'
-zre 's|(Value[0-9]{1,2} [0-9a-z]{8}\n)(.*)\n|\1|g'


我该怎么办?我认为问题出在\n上,因为当我删除它时,示例可以工作(但仍然不是预期的输出)。

fxnxkyjh

fxnxkyjh1#

使用GNU awk:

$ awk '{where=match($0,"Value[0-9]{1,2} [0-9a-z]{8}"); if (where) {print; getline} else {print}}' file
ServerA
Value1 fh824rfz
ServerB
Value3 9fgjzxlo
ServerC
Value10 339fgh0l

字符串

kuarbcqp

kuarbcqp2#

使用您显示的示例,请尝试以下awk代码。使用awkmatch函数,其中使用regex来获取匹配值。

awk -v RS="" '
{
  while(match($0,/Value[0-9]+ [0-9a-z]{8}\n[^\n]*/)){
    val=substr($0,RSTART,RLENGTH)
    split(val,arr,ORS)
    prevLine=substr($0,1,RSTART-1)
    gsub(/^\n+|\n+$/,"",prevLine)
    print prevLine ORS arr[1]
    $0=substr($0,RSTART+RLENGTH)
  }
}
'  Input_file

字符串

smdncfj3

smdncfj33#

哇,所有的教授都聚集在这里。我也可以提出一个方法吗?😉

awk --posix '/Value[0-9]{1,2} [0-9a-z]{8}/ { print prev ORS $0 } { prev = $0 }' data.txt

#OR

awk --posix '/Value[0-9]{1,2} [0-9a-z]{8}/ { print prev; print $0 } { prev = $0 }' data.txt

字符串
产出:

ServerA
Value1 fh824rfz
ServerB
Value3 9fgjzxlo
ServerC
Value10 339fgh0l

iugsix8n

iugsix8n4#

$ grep -v -f <(
     grep -P -A 1 "Value[0-9]{1,2} [0-9a-z]{8}" file |
     grep -P -v "Value[0-9]{1,2} [0-9a-z]{8}"
 ) file
ServerA
Value1 fh824rfz
ServerB
Value3 9fgjzxlo
ServerC
Value10 339fgh0l

字符串

p4rjhz4m

p4rjhz4m5#

$0保存在awk中,然后使用虚拟getline来“删除下一行”,方法是利用其返回代码作为substr()的起始索引,并使用赋值来用当前行覆盖“下一行”:

jot 10 |
mawk '(__ = $_)~/[3-7]/ && $!NF = substr(__, getline)'
3
5
7
iyzzxitl

iyzzxitl6#

这里有一种方法(使用GNU sed检查,语法可能因其他实现而异):

$ sed -E '/Value[0-9]{1,2} [0-9a-z]{8}$/{n; d}' ip.txt
ServerA
Value1 fh824rfz
ServerB
Value3 9fgjzxlo
ServerC
Value10 339fgh0l

字符串
n命令打印图案空间(如果-n选项未禁用自动打印),将其替换为下一行,d将删除它。

xmq68pz9

xmq68pz97#

默认情况下,sed是基于行的,你不能像在前两个尝试中那样一次处理多行。例如,要应用你的策略,你必须将下一行连接到当前行(N命令),然后处理这个由两行组成的块:

sed -E '/Value[0-9]{1,2} [0-9a-z]{8}$/{N;s/\n.*//}'

字符串
另一种解决方案,如果您使用的是GNU sed,如果您的文件不是太大,并且不包含NUL字节(ASCII码0),是使用-z选项将整个文件作为一行插入换行符(使用-z选项时,sed认为输入行由NUL字节而不是换行符终止):

sed -Ez 's/(Value[0-9]{1,2} [0-9a-z]{8}\n)[^\n]*\n/\1/g'


这几乎是你在第三次尝试时所尝试的,但是由于你使用的(.*)组匹配了包括换行符在内的所有字符,所以你只打印了第一组...在第三次尝试中将(.*)替换为[^\n]*应该可以工作。另请注意,当您要抑制它时,不需要进行分组。
使用GNU sed,您还可以使用s命令的多行模式(m修饰符),这样句点就不匹配换行符:

sed -Ez 's/(Value[0-9]{1,2} [0-9a-z]{8}\n).*\n/\1/gm'


由于其他人也提出了awk解决方案,这里是一个简单的:

awk 's{s=0;next} /Value[0-9]{1,2} [0-9a-z]{8}$/{s=1} 1'


也就是说,如果变量s不同于0(或空字符串),则将其重置为0并跳过当前行(next)。否则,如果当前行与正则表达式匹配,则将变量s设置为1。最后,打印当前行(1)。

3okqufwl

3okqufwl8#

sed通常不是一次处理多个输入行的最佳工具。
使用任何POSIX awk,一次只在内存中存储1行:

$ awk '!f; {f=(/^Value[0-9]{1,2} [0-9a-z]{8}$/)}' file
ServerA
Value1 fh824rfz
ServerB
Value3 9fgjzxlo
ServerC
Value10 339fgh0l

字符串

相关问题