String 高效/安全的shell脚本,用于从分隔的拆分字符串中删除所有子字符串匹配项?
对于由分隔符“:”分割的字符串,在分隔符之间匹配包含不同字符串“XXX”的所有子字符串的最佳方法是什么 比如说,首先String 高效/安全的shell脚本,用于从分隔的拆分字符串中删除所有子字符串匹配项?,string,bash,shell,awk,sed,String,Bash,Shell,Awk,Sed,对于由分隔符“:”分割的字符串,在分隔符之间匹配包含不同字符串“XXX”的所有子字符串的最佳方法是什么 比如说,首先 /aa/:/a/b/XXX/:/bb/bb:/c/XXXd/e/f/:/cc/cc/ 删除所有包含“XXX”的部分——可以是任何位置的任何实例——以 /aa/:/bb/bb:/cc/cc/ bash可以直接这样做吗?使用awk或sed更好?因此,您想要消除的每个条目都是一系列非:,其中包含XXX,在正则表达式世界中是[^:]*XXX[^:]* 但是您还希望消除它后面的:,这意
/aa/:/a/b/XXX/:/bb/bb:/c/XXXd/e/f/:/cc/cc/
删除所有包含“XXX”的部分——可以是任何位置的任何实例——以
/aa/:/bb/bb:/cc/cc/
bash可以直接这样做吗?使用awk或sed更好?因此,您想要消除的每个条目都是一系列非
:
,其中包含XXX
,在正则表达式世界中是[^:]*XXX[^:]*
但是您还希望消除它后面的:
,这意味着您希望匹配并消除[^:]*XXX[^:]*:
事实上,如果某个字段恰好是最后一个字段,则不允许删除该字段,该字段包含XXX
;要解决此问题,您需要匹配行尾作为关闭的替代方法,因此命令是
sed-E的//[^:]*XXX[^:]*(:|$)//g'该文件
但是这仍然有一个问题:只要最后一项匹配,它就会留下一个尾随的:
。为了解决这个问题,我们只需运行另一个临时替换,因此完整的Sed命令如下:
sed-E的//[^:]*XXX[^:]*(:|$)//g;s/:$/“该文件
我们真的需要s
usbstitution命令吗
Sed没有lookaheads,这意味着我们匹配的任何内容都会被消耗,并且不能通过相同的s
命令再次匹配,即使有g
标志
另一方面,我们希望将包含XXX
的字段与其周围的两个:
中的一个(而不是两个)一起删除
如果我们像我一样选择了正确的:
,那么很明显,如果最后一个字段(与行的尾端匹配,而不是:
)匹配XXX
,它将留下一个尾随:
(除非所有字段都匹配XXX
,在这种情况下,结果是空字符串)
这意味着一个s
substitution命令无法为用例的所有场景提供“干净”的答案
如我所示,使用两个
s
命令就足以解决此问题。下面是一个解决此问题的awk:
awk ' BEGIN {FS=OFS=":"}
{s="";
for (i=1;i<=NF;i++) {
if ($i~/XXX/) continue;
s=s OFS $i
}
print s
}' file
awk'BEGIN{FS=OFS=“:”}
{s=”“;
对于(i=1;i,对于多字符RS和RT,GNU awk:
$ awk -v RS=':' '{ORS=RT} !/XXX/' file
/aa/:/bb/bb:/cc/cc/
为了适应恩里科在下面的评论中提到的情况
$ cat file
/aa/:/a/b/XXX/:/bb/bb:/c/XXXd/e/f/:/cc/cc/
$ cat file1
/bb/bb:/aXXX/b/
您可以使用GNU awk为多字符RS执行此操作:
$ awk -v RS='[:\n]' '!/XXX/{printf "%s%s", sep, $0; sep=":"} END{print ""}' file
/aa/:/bb/bb:/cc/cc/
$ awk -v RS='[:\n]' '!/XXX/{printf "%s%s", sep, $0; sep=":"} END{print ""}' file1
/bb/bb
或使用任何awk:
$ awk -v RS=':' '!/XXX/{sub(/\n/,""); printf "%s%s", sep, $0; sep=":"} END{print ""}' file
/aa/:/bb/bb:/cc/cc/
$ awk -v RS=':' '!/XXX/{sub(/\n/,""); printf "%s%s", sep, $0; sep=":"} END{print ""}' file1
/bb/bb
也许XXX
字符串可能会出现在一行的开头,因此可能sed-E的/:?[^:]*XXX[^:]*//g'文件
?@potong,如果XXX
出现在第一个字段,而不是所有其他字段,例如sed-E的/:?[^:]*XXX[^:]*//g'这仍然在像/aXXX/b/:/bb/bb
这样的输入上保留了一个前导的:
。这可以通过将s=s of s$i
更改为if(s==“”){s=$i}或者{s=s of s$i}来解决
。如果输入是/bb/bb:/aXXX/b/
,这仍然会忘记删除:
,但是+1。@EnricoMariaDeAngelis更糟糕的是,它没有生成终止换行符,因此输出不是有效的POSIX文本文件。感谢提醒,我现在已经修复了它。哦,对了,因为POSIX行与^[^\n]*\n
,我没有想到。这意味着,即使我想,我也不能通过管道将输出传输到另一个工具(如sed)来删除终止的:
,因为根据POSIX,这是未定义的行为。