Segmentation fault in der bash-Skript mit find, grep, sed
Ich habe ein Skript, dass die suchen über eine sehr große Anzahl von Dateien, und nutzt sed zu ersetzen mehrzeilige Muster. Das Skript ist iterativ, und es funktioniert gut auf einige Iterationen, aber manchmal verursacht es einen segmentation fault.
Dies ist, was das Skript tut:
- Suche nach Dateien, die NICHT enthalten die Zeichenfolge X
- Aus diesen Dateien, suchen diejenigen, die die Zeichenfolge ENTHALTEN Y
- Durchlaufen der zurückgegebenen file-Liste mit einer for-Schleife
- Wenn Sie den Inhalt der Datei übereinstimmen, Muster, pattern ersetzen Eine mit A_TAG
- Das gleiche für die Muster B,C,D (kann eine Datei enthalten, nur für A,B,C,D)
Muster A,B,C,D sind multiline und ersetzt werden Sie mit zwei Linien. X und Y sind einzelne Linie.
Hier ist das Skript. Ich entschuldige mich für die langen Zeilen, aber ich beschloss, nicht, um Sie zu Bearbeiten, da Sie regex. Ich habe allerdings verkürzen die regex durch ersetzen von Zeichenfolgen, die mit "Muster" - der Inhalt ersetzt NICHT die gleichen in jedem regex, aber Sie haben nicht alle Sonderzeichen, so dass ich glaube nicht, dass die eigentlichen Inhalte sind relevant für diese Frage. Neben der regex hat sich gezeigt, zu arbeiten, so dass Sie wahrscheinlich nicht brauchen, es zu verstehen..
#!/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
Vielleicht sollte ich beachten Sie, dass C ist im wesentlichen eine längere version von D, die hat einige zusätzliche Inhalte, bevor der Allgemeine Teil.
Was passiert, ist, dass für einige Iterationen dies funktioniert ok..
####################
Working on file ./src/listing.txt
A
In multil_sed
Done
####################
und manchmal nicht.
####################
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
####################
Es ist nicht abhängig von dem Muster, nach dem gesucht wird.
####################
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
####################
Linie 54 Punkte auf der Zeile "for p in $(find . -type f -not-iwholename '.git' -exec grep...".
Meine Vermutung ist, dass die sed verursacht einen buffer overflow, aber ich habe nicht gefunden, einen Weg, um festzustellen, oder beheben diese.
- Bevor jemand erwähnt ack-grep - ja, ich weiß, über ack-grep. Ich benutzte es zunächst, wechselte aber zur find-exec in der Hoffnung, dass würde dieses Problem beheben.
- Wenn Sie versuchen, analysieren von C++ mit regulären Ausdrücken bereit sein, hand-überprüfen Sie jede einzelne Ersetzung vorgenommen, weil C++ ist keine reguläre Sprache und regexps nicht umgehen kann, alle Kontext-freien Grammatiken.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Bash ist nicht so toll zum Auffinden der Quelle eines Fehlers in einer compound-Anweisung, so
ist irreführend, da der Fehler überall sein könnte in dieser for-Anweisung block. Die Fehlermeldung
ist viel genauer. Und wahrscheinlich die Ursache für den Fehler ist die
-M
Flagge kombiniert mit unendlicher Muster wie(.|\n)*
Als Xen Mann Seite Hinweise:mit Hervorhebung von mir. Das single-Muster-fragment
.*
oder(.|\n)*
können buchstäblich übereinstimmen, eine ganze Datei, also ja, es wird füllen Sie Ihre lookahead-buffer nicht einfach zum nächsten literal (z.B.http
) aber bis es findet die Letzte derartige wörtliche, weil standardmäßig reguläre Ausdrücke suchen, die längste konform übereinstimmen.UPDATE #2: Also anscheinend sed nicht unterstützt non-greedy matching, das macht einen Teil meiner Antwort ungültig. Es gibt Möglichkeiten, um dieses, aber ich nicht hier, da es weit entfernt von der ursprünglichen Frage. Die Antwort auf diese Frage ist mit der --disable-stack-für-Rekursion-flag, wie unten beschrieben.
Die Antwort von msw hat mir geholfen, in die richtige Richtung.
Zuerst änderte ich die regex-zu faul sein, statt gierig. Standardmäßig regex gierig, die (wie msw angegeben) bedeutet, dass ein mehrzeiliger Ausdruck mit "MUSTER" (.|\n)*TEXT" durchsucht die ganze Datei. Durch hinzufügen von "?" nach Quantoren (* -> *?) Ich habe die regez faul, was bedeutet, dass die "(.|\n)*?" in "MUSTER" (.|\n)*?TEXT" stop dem ausbau bei den ersten TEXT.
Ich habe auch die optionalen Teile faul (? -> ??), obwohl, ich bin mir nicht sicher, ob dies war notwendig.
Jedoch war dies nicht genug. Ich hatte auch zum konfigurieren von Xen zu verwenden, heap anstelle von stack-Speicher. Ich heruntergeladen habe, pcre und konfiguriert werden mit dem flag --disable-Stacks für Rekursion. Beachten Sie, dass die Verwendung heap viel langsamer, also sollte man nicht tun, wenn Sie nicht haben, um.
Ich bin auch ein Schritt-für-Schritt-falls jemand fragt hier mit dem gleichen problem. Beachten Sie, dass ich bin immer noch linux-newb und es gibt eine hohe Wahrscheinlichkeit, dass ich etwas unnötig und/oder dumm. Die Anleitung basiert auf http://www.mail-archive.com/[email protected]/msg00817.html und http://www.linuxfromscratch.org/blfs/view/svn/general/pcre.html
Sind einige zusätzliche Schritte in der mitgelieferten Anleitung, aber ich habe nicht, Sie zu tun.
UPDATE: die optionalen Elemente lazy (? -> ??) ist ein Fehler, denn dann werden Sie nicht eingeschlossen in der abgestimmten Muster, wenn möglich.