Wie verwende ich die Grep-Ausgabe als Pfad für eine CD?

9

Wie kann ich die grepAusgabe als Argument an den cdBefehl weiterleiten?

Zum Beispiel:

[root@xxx xxx]# pip install django | grep '/usr.*'  
Requirement already satisfied (use --upgrade to upgrade): django in   /usr/lib64/python2.7/site-packages

Hier /usr/lib64/python2.7/site-packagesist hervorgehoben und ich möchte diese Zeichenfolge an übergeben cd.

Micgeronimo
quelle

Antworten:

16

Verwenden Sie die Befehlsersetzung von Bash $(), die Sie auch -omit grep benötigen, um nur den übereinstimmenden Teil auszuwählen:

cd "$(pip install django | grep -o '/usr.*')"

Beachten Sie, dass , obwohl Sie in diesem Fall weg, aber Sie sollten den Befehl Substitution mit doppelten Anführungszeichen immer einschließen , so dass der Schal nicht durchführt Wort Spaltung auf Whitespaces (standardmäßig Leerzeichen, Tabulator und Newline, auf dem abhängig IFSVariable bei bash).

heemayl
quelle
9

Abhängig davon, was Sie tun und vorher nicht wissen, was pipausgegeben wird, können Sie sich grepfür etwas anderes entscheiden als /usr.*.

Wenn Sie wissen, dass das Verzeichnis mit beginnt/usr (und dass es am Ende der Ausgabezeile von angezeigt pipwird und dass /usres nirgendwo in der Zeile vor dem Verzeichnisnamen angezeigt wird), ist dies eine gute Wahl. heemayls antwort sagt dir wie.

Wenn der Grund , Sie wissen es beginnt mit /usrist , dass Sie nur den Befehl ausführen und kennen das Verzeichnis , das Sie ändern möchten, schlage ich die einfachere Lösung den Befehl ausgeführt wird cd /usr/lib64/python2.7/site-packages. Dies ist weniger tippend, selbst wenn Sie die Tab-Vervollständigung nicht verwenden .

Andernfalls können Sie einen anderen regulären Ausdruck auswählen, je nachdem, was Sie über die zu analysierende Ausgabe wissen. Bei allen folgenden Alternativen wird weiterhin davon ausgegangen, dass der Verzeichnisname am Ende der Zeile angezeigt wird, die anderen Annahmen variieren jedoch.

Wenn Sie wissen, dass der Verzeichnisname absolut ist (dh mit a beginnt /) und /in der Zeile vor dem Verzeichnisnamen kein angezeigt wird , können Sie denselben regulären Ausdruck wie in der Antwort von heemayl verwenden, jedoch mit /anstelle von /usr:

cd "$(pip install django | grep -o '/.*')"

Dies entspricht einem /gefolgt von null oder mehr ( *) eines beliebigen Zeichens ( .).

Wenn Sie wissen, dass der Verzeichnisname kein horizontales Leerzeichen (keine Leerzeichen oder Tabulatoren) enthält und am Ende der Zeile angezeigt wird , können Sie Folgendes verwenden:

cd "$(pip install django | grep -oP '[^\h]+$')"

Hier habe ich einen Perl-regulären Ausdruck ( -P) verwendet, da die \hAbkürzung (für [:blank:]) das Eingeben und Lesen erleichtert als ein gleichwertiger erweiterter regulärer Ausdruck ( -E). Dies entspricht einem oder mehreren ( +) Zeichen in einer Zeichenklasse ( [ ]), die kein ( ^) Leerzeichen oder Tabulator ( \h) ist.

Wenn Sie wissen , dass dem Verzeichnisnamen unmittelbar ein inhorizontales Leerzeichen vorangestellt ist (dh links und rechts mit Leerzeichen aufgefüllt ist) und dass dies das einzige derartige Vorkommen inin der Zeile ist , können Sie Folgendes verwenden:

cd "$(pip install django | grep -oP '\hin\h+\K.+')"

Hierbei wird eine positive Look-Behind-Zusicherung ( \K) mit einer Breite von Null verwendet , um ein oder mehrere Zeichen ( .+), die nach einem Leerzeichen oder Tabulator ( \h) erscheinen in, und ein oder mehrere Leerzeichen oder Tabulatoren ( \h+) abzugleichen , ohne indie Leerzeichen tatsächlich einzuschließen umgibt es im Spiel. Look-Around-Behauptungen sind ein Merkmal regulärer Perl-Ausdrücke.

Das Muster hätte auch funktioniert, aber wir müssen vorher nur nach einem Leerzeichen suchen , unabhängig davon, wie viele vorhanden sind. Im Gegensatz dazu müssen wir alle Leerzeichen nachher abgleichen , sonst werden sie nicht von verworfen und als Teil des Verzeichnisnamens abgeglichen.\h+in\h+\K.+inin\K

Wenn Sie wissen, dass dem Verzeichnisnamen unmittelbar das letzte Vorkommen der Zeile ingefolgt von einem horizontalen Leerzeichen vorausgeht , können Sie Folgendes verwenden:

set +H
cd "$(pip install django | grep -oP '\hin\h+(?!.*\hin\h.*)\K.*')"
set -H

Dort enthält die positive Look-Behind-Behauptung mit der Breite Null selbst eine negative Look-Ahead-Behauptung mit der Breite Null ( (?! )).

Das !erscheint so, dass es schwierig ist , elegant zu entkommen ; Die Methode, mit der ich verhindert habe, dass die Shell- Verlaufserweiterung ausgelöst wird, bevor sie an übergeben wird, grepbesteht darin, die Verlaufserweiterung ( set +H) vor dem Ausführen des Befehls vorübergehend zu deaktivieren und anschließend erneut zu aktivieren ( set -H). Wenn Sie dies in einem Skript verwenden und Ihr Skript es nicht enthält set -H, müssen Sie dies nicht tun, da die Verlaufserweiterung nur dann automatisch aktiviert wird, wenn eine Shell interaktiv ausgeführt wird.

Beachten Sie schließlich, dass weder diese noch Heemayls Antwort tatsächlich die Ausgabe von grepan weiterleitencd (obwohl die Ausgabe von pipnoch an weitergeleitet wird grep). Anstelle von Pipes ist das geeignete Werkzeug für diesen Job die Befehlssubstitution .

Eliah Kagan
quelle
Wenn Sie technische Informationen benötigen , verwendet die Shell natürlich eine interne Pipe, um die Befehlsausgabe zu lesen.
Random832
@ Random832 Guter Punkt - Ich habe diesbezüglich etwas bearbeitet. Übrigens, wissen Sie, ob Sie sich auf die Verwendung von Rohren "unter der Haube" bei der Befehlsersetzung verlassen können? Oder handelt es sich um ein Implementierungsdetail, das in einer anderen, zukünftigen Version von Bash möglicherweise anders ausgeführt wird? (Natürlich verstehe ich in der Praxis, dass dies der beste Weg ist, und daher ist es unwahrscheinlich, dass es anders implementiert wird.)
Eliah Kagan
1
Nein, es ist nicht garantiert, theoretisch könnte eine Shell eine benannte FIFO- oder temporäre Datei verwenden, obwohl es keinen Grund dafür gibt.
Random832
Sind Sie sicher über die Erweiterung der Geschichte? Die einzigen Zeichen, die es blockieren können, sind ` and '`, und Sie haben einfache Anführungszeichen um den grep-Ausdruck verwendet.
Muru
1
@muru Ja, es ist erweitert. Ich hatte es auch nicht bemerkt, fand es aber heraus, als ich es testete. Das !dort wird nicht mit '-zitaten zitiert , da die '-zitate selbst zitiert werden. Die Komplexität des Befehls macht es leicht, seine Wirkung falsch vorherzusagen, aber anscheinend! funktioniert er aufgrund der Reihenfolge der Erweiterungen ( ist früh) wie x=foo; echo "'$x'"(-> 'foo'). Das Entfernen der äußeren "Anführungszeichen würde !zu 'Anführungszeichen führen und die Erweiterung des Verlaufs verhindern. Dies würde jedoch cd fehlschlagen, wenn das Verzeichnis Leerzeichen enthält.
Eliah Kagan