2016-11-29 13 views
0

Ich versuche, eine Suche mit Git zu starten, um mir alle gestaffelte Dateien in einem von zwei Ordnern zu erhalten: lokalen oder Komponenten. Ich möchte nur JS-Dateien bekommen. Der Befehl wird in der Konsole ausgeführt.Regulärer Ausdruck für beginnt mit und endet mit

Was ich habe, so weit:

STAGED_FILES=($(git diff --cached --name-only --diff-filter=ACM | grep "^(local|components).*?.js")) 

Dies wird mir alle inszenierten Dateien:

git diff --cached --name-only --diff-filter=ACM 

Dies wird mir alle Wege Dateien mit lokalen oder Komponenten in

grep "^(local|components)" 

Und das bringt mir alle js Dateien

grep ".js" 

Und das gibt mir nichts aus irgendeinem Grund:

($(git diff --cached --name-only --diff-filter=ACM | grep "^(local|components).*?.js")) 

Was ist der reguläre Ausdruck, den ich mit, dass die Suche könnte, würde mir alle js Dateien in diesen beiden Ordnern bekommen?

Antwort

4

Es hat nicht funktioniert, weil grep keine faulen Übereinstimmungen ? unterstützt. Sie können -E für erweiterte reguläre Ausdrücke verwenden.

Zum Beispiel betrachten diese

$ echo "asfasdfzasdfasdfz" | grep -E "a.*?z" 
asfasdfzasdfasdfz 
$ echo "asfasdfzasdfasdfz" | grep "a.*?z" 
$ echo "asfasdfzasdfasdf?z" | grep "a.*?z" 
asfasdfzasdfasdf?z 

Wie Sie ohne -E sehen es versucht ? auch innerhalb der Zeichenfolge übereinstimmen.

+0

Ich wusste das nicht, danke! – SoluableNonagon

+0

@SolubleNonagon Sie sind willkommen :) – nu11p01n73R

2

Neben den regulären Ausdruck basiert antwortet, können Sie dies direkt in Git, tun, die den Begriff einer „Pfadangabe“ einschließlich Shell-Stil Globbing hat:

git diff --cached --name-only \ 
    --diff-filter=ACM -- 'local/**/*.js' 'components/**/*.js' 

(Linie für die Anzeige Formatierung gebrochen, beachten Sie, dass die ** Unterstützung ist neu in Git Version 1.8.2).

Das heißt, reguläre Ausdrücke sind "leistungsfähiger" als Shell-Globs, also sollten Sie nu11p01n73R's answer im Hinterkopf behalten. Beachten Sie jedoch, dass nicht gierige Matches (*?) Spiel als wenig wie möglich und nicht als viele wie möglich:

pattern  input  result (matched part in parentheses) 

abc.*e  0abcdefeged  0(abcdefege)d 
abc.*?e 0abcdefeged  0(abcde)feged 
abc.*d  0abcdefeged  0(abcdefeged) 
abc.*?d 0abcdefeged  0(abcd)efeged 

Ihren Ausdruck, ^(local|components).*?.js, sagt (in erweiterten Interpretationen sowieso): Spiel der Anfang der Linie; dann entweder local oder components als wörtlichen Text entsprechen; dann passen Sie so wenige Zeichen wie möglich an, vielleicht keine; dann mit einem beliebigen Zeichen übereinstimmen; dann mit einem Literal übereinstimmen j; dann ein Literal s übereinstimmen. Daher entspricht dies local-jaguar-xjs-vehicles, weil es mit local beginnt, enthält einen Text, hat ein Zeichen mehr vor js und geht weiter.

Die Schale glob Muster local/**/*.js Einstimmungen nur das Verzeichnis local, von einer beliebigen Anzahl-ggf. Null-Unterverzeichnis von Komponenten, gefolgt von einem Dateinamen gefolgt, deren Enden mit .js, mit dem Punkt buchstäblich abgestimmt. Das entspricht also dem Muster ^local/(.*/|)[^/]*\.js$: der am Anfang der Zeile übereinstimmende Literaltext local gefolgt von einem Schrägstrich; gefolgt von entweder: einer beliebigen Anzahl von Zeichen, die mit einem Schrägstrich enden (so viele wie möglich) oder gar nichts; gefolgt von einer beliebigen Zahl (einschließlich keine) eines beliebigen Zeichens außer Schrägstrich, gefolgt von einem Literal .js, gefolgt vom Ende der Zeile.

Beachten Sie, dass, weil dieser Ausdruck an beiden Enden verankert ist (muss am Anfang und Ende der Leitung entsprechen), und es gibt nur eine Kleene star in der Mitte, es ist nicht, ob wir ein gierig oder nicht verwenden egal greedy match: Der linke Anker passt auf der linken Seite und der rechte Anker auf der rechten Seite, und eine gierige Übereinstimmung nimmt so viel von der Mitte wie möglich - also alles - während ein nicht-gieriges Match dauert wie wenig der Mitte, wie es kann ... was immer noch "alles davon" ist.

(Dies setzt natürlich voraus, dass die Dateinamen mit nur einer Datei pro Zeile gedruckt werden. Zum Glück git diff --name-only tut genau das. Shell ** für "beliebig viele Verzeichnisse" wird nicht in allen Shells unterstützt. noch alle Nicht-Shell-Dateinamen globbing, aber es ist in Git verwendet pathspecs (Suche nach "pathspec").)

+0

Das hilft wirklich viel. Vielen Dank. – SoluableNonagon

Verwandte Themen