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:

  1. Suche nach Dateien, die NICHT enthalten die Zeichenfolge X
  2. Aus diesen Dateien, suchen diejenigen, die die Zeichenfolge ENTHALTEN Y
  3. Durchlaufen der zurückgegebenen file-Liste mit einer for-Schleife
  4. Wenn Sie den Inhalt der Datei übereinstimmen, Muster, pattern ersetzen Eine mit A_TAG
  5. 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.
InformationsquelleAutor T.Kaukoranta | 2013-05-31
Schreibe einen Kommentar