Reguläre Ausdrücke in Linux Befehl sed
Habe ich eine shell-variable:
all_apk_file="a 1 2.apk x.apk y m.apk"
Möchte ich ersetzen die a 1 2.apk
mit TEST
, mit dem Befehl:
echo $all_apk_file | sed 's/(.*apk ){1}/TEST/g'
Den .*apk
bedeutet Ende mit apk
, {1}
bedeutet nur eine Zeit, aber es funktioniert nicht; ich habe nur die original-variable, die als Ausgabe: a 1 2.apk x.apk y m.apk
Kann mir jemand sagen warum?
- Die kurze Antwort ist sed ist gierig. Da setzen Sie
.*
Sie schnappen die ersten zwei " apk " - Kombinationen als Teil.*
und so erkennt nur die letztenapk
als die endgültige Kombination.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Einem Teil des Problems ist, dass in regelmäßigen
sed
, die()
und{}
sind gewöhnliche Zeichen im Muster bis entkam mit backslashes. Da gibt es keine Klammern in der variable Wert, die regex nie Spiele. Mit GNUsed
Sie können auch aktivieren Sie die erweiterten regulären Ausdrücke, die mit der-r
Flagge. Wenn Sie das problem beheben, Sie führen Sie dann in das problem, dass.*
ist gierig, und dieg
Modifikator tatsächlich ändert sich nichts:Es wird nur beendet, denn da gibt es nicht einen Raum nach
m.apk
im echo den Wert der Variablen.Die Frage ist jetzt: was ist es, das Sie ersetzen möchten? Es klingt wie " alles, was bis zu und einschließlich dem ersten vorkommen von
apk
am Ende eines Wortes. Dies ist wahrscheinlich am einfachsten mit einem Rahmen oder non-greedy matching, wie Sie in Perl reguläre Ausdrücke. Wenn der Wechsel zu Perl ist eine option, dies zu tun. Wenn nicht, ist es nicht trivial, im normalensed
reguläre Ausdrücke.Das sieht für alles, was ohne Punkte in ihm, gefolgt von einem Leerzeichen, gefolgt von no dots wieder, und
.apk
; dies bedeutet, dass der erste Punkt erlaubt ist, ist das man in2.apk
. Es funktioniert für die sample-Daten; es würde nicht funktionieren, wenn die variable enthalten:Müssen Sie tune diese um Ihre Anforderungen zu erfüllen.
Ersten, damit die regulären Ausdrücke, die Sie vertraut sind mit in
sed
verwenden, benötigen Sie die-r
Schalter (sed -r ...):Schauen, was es gibt:
TESTy m.apk
. Dies ist, weil die.*
ist gierig, so entspricht so viel wie möglich. Das heißt, die.*
entsprichta 1 2.apk x
, und Sie haben gesagt, Sie ersetzen möchten.*apk
, wirda 1 2.apk x.apk
mit 'TEST', was inTESTy m.apk
(beachten Sie das Leerzeichen nach dem".apk' im regulären Ausdruck, das ist der Grund, warum das match nicht den ganzen Weg erstreckt, um das Letzte '.apk', die keine Leerzeichen nach es).In der Regel man könnte die
.*
zu.*?
zu machen nicht gierig, aber dieses Verhalten ist nicht unterstützt in der sed.So, um es zu beheben müssen Sie nur Ihre regex restriktiver.
Es ist schwer zu sagen, was Sie tun möchten - entfernen Sie die ersten drei Worte, wo der Dritte endet in".apk' und ersetzen durch 'TEST'? In diesem Fall könnte man den regulären Ausdruck:
in Kombination mit dem 'ich' wechseln (groß-und Kleinschreibung).
Haben Sie zu geben, Ihre Logik für die Entscheidung, was zu entfernen (die ersten drei Worte, alle Worte bis zum ersten".apk' word, etc), damit wir Ihnen weiter helfen mit der regex.
Zweitens, Sie habe die " g " - Schalter in deinem regex. Dies bedeutet, dass alle passenden mustern ersetzt werden, und Sie scheinen zu wollen, nur das erste ersetzt werden. So entfernen Sie die " g " - Schalter.
Schließlich, alle thse in Kombination:
echo $all_apk_file | perl -pe 's/^(.*?\.apk)/TEST/'
wenn der Wechsel zu perl ist eine option.Könnte dies für Sie arbeiten:
Warum regexp nicht funktioniert siehe @mathematische.Kaffee und @Jonathan Leffler ' s ausgezeichnete Erläuterungen.
s/apk/\n/
ist gleichbedeutend mits/apk/\n/1
was bedeutet, ersetzt das erste auftreten vonapk
mit\n
. Als sed verwendet die\n
als Datensatz-Trennzeichen wir wissen, dass es nicht auftreten, in einem ersten strings, der an die sed-Befehle. Mit diesen beiden Tatsachen unter unserem Gürtel können wir split strings.N. B. Wenn Sie wollte, Sie zu ersetzen bis zu dem zweiten
apk
danns/apk/\n/2
würde die Rechnung passen. Der Kurs für die letzten vorkommen desapk
dann.*apk
ins Spiel kommt.