我有一个脚本可以搜索大量文件,并使用 sed 替换多行模式。该脚本是迭代的,它在某些迭代中运行良好,但有时会导致分段错误。
这就是脚本正在做的事情:
- 搜索不包含字符串 X 的文件
- 在这些文件中,搜索包含字符串 Y 的文件
- 使用 for 循环迭代返回的文件列表
- 如果文件内容与模式 A 匹配,则将模式 A 替换为 A_TAG
- 模式 B、C、D 相同(文件只能包含 A、B、C、D 之一)
模式 A、B、C、D 是多行的,它们被替换为两行。X 和 Y 是单行。
这是脚本。我为长线道歉,但我决定不编辑它们,因为它们是正则表达式。然而,我确实通过用“模式”替换字符串来缩短正则表达式 - 每个正则表达式中的替换内容都不相同,但它们没有任何特殊字符,所以我认为实际内容与这个问题无关。此外,正则表达式已被证明可以工作,因此您可能不需要完全理解它。
#!/bin/sh
STRING_A="Pattern(\n|.)*Pattern\.\""
A_TAG="\$STRING:A$"
STRING_B="(Pattern(\n|.)*)?(Pattern(\n|.)*)?Pattern(\n|.)*Pattern(\n|.)*Pattern\.((\n|.)*will be met\: http\:\/\/www.foo\.org\/example\/temp\.html\.\n)?"
B_TAG="\$STRING:B$"
STRING_C="(Pattern(\n|.)*)?Pattern(\n|.)*http\:\/\/www\.foo\.org\/bar\/old-foobar\/file\-2\.1\.html\.((\n|.)*Pattern.*Pattern)?"
C_TAG="\$STRING:C$"
STRING_D="(Pattern(\n|.)*)?(Pattern(\n|.)*http\:\/\/www\.foo\.org\/bar\/old-foobar\/file\-2\.1\.html.*|Pattern(\n|.)*Pattern)((\n|.)*http\:\/\/www\.some-site\.org/\.)?"
D_TAG="\$STRING:D$"
## params: #1 file, #2 PATTERN, #3 TAG
multil_sed()
{
echo "In multil_sed"
# -n = silent, -r = extended regex, -i = inline changes
sed -nr '
# Sed has a hold buffer that we can use to "keep text in memory".
# Here we copy the line to the buffer if it is the first line of the file,
# or append it if it is not
1h
1!H
# We must first save all lines until the nth line to the hold buffer,
# then we can search for our pattern
60 {
# Then we must use the pattern buffer. Pattern buffer holds text that
# is up for modification. With g we can hopy the hold buffer into the pattern space
g
# Now we can just use the substitution command as we normally would. Use @ as a delimiter
s@([ \t:#*;/".\\-]*)'"$2"'@\1'"$3"'\
\1$QT_END_LICENSE$@Ig
# Finally print what we did
p
}
' $1 > $1.foo;
echo "Done"
}
for p in $(find . -type f -not -iwholename '*.git*' -exec grep -iL '.*STRING_X.*' {} \; | xargs grep -il -E '.*STRING_Y.*')
do
echo
echo "####################"
echo "Working on file" $p
#Find A
if pcregrep -qiM "$STRING_A" "$p";
then
echo "A"
multil_sed "$p" "$STRING_A" "$A_TAG"
#Find B
elif pcregrep -qiM "$STRING_B" "$p";
then
echo "B"
multil_sed "$p" "$STRING_B" "$B_TAG"
#Find C
elif pcregrep -qiM "$STRING_C" "$p";
then
echo "C"
multil_sed "$p" "$STRING_C" "$C_TAG"
#Find D
elif pcregrep -qiM "$STRING_D" "$p";
then
echo "D"
multil_sed "$p" "$STRING_D" "$D_TAG"
else
echo "No match found"
fi
echo "####################"
done
我可能应该注意到 C 本质上是 D 的更长版本,在公共部分之前有一些额外的内容。
发生的情况是,对于某些迭代,这可以正常工作..
####################
Working on file ./src/listing.txt
A
In multil_sed
Done
####################
有时它不会。
####################
Working on file ./src/web/page.html
/home/tekaukor/code/project/tag_adder.sh: line 54: 16904 Segmentation fault (core dumped) pcregrep -qiM "$STRING_A" "$p"
No match found
####################
它不依赖于正在搜索的模式。
####################
Working on file ./src/test/formatter_test.cpp
/home/tekaukor/code/project/tag_adder.sh: line 54: 18051 Segmentation fault (core dumped) pcregrep -qiM "$STRING_B" "$p"
/home/tekaukor/code/project/tag_adder.sh: line 54: 18053 Segmentation fault (core dumped) pcregrep -qiM "$STRING_C" "$p"
/home/tekaukor/code/project/tag_adder.sh: line 54: 18055 Segmentation fault (core dumped) pcregrep -qiM "$STRING_D" "$p"
No match found
####################
第 54 行指向“for p in $(find . -type f -not -iwholename ' .git ' -exec grep...”行。
我的猜测是 sed 导致缓冲区溢出,但我还没有找到确定或解决此问题的方法。