Come usare l'output grep come percorso per cd?


9

Come posso pipe grepoutput come argomento per il cdcomando?

Per esempio:

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

Qui /usr/lib64/python2.7/site-packagesè evidenziato e voglio passare questa stringa a cd.

Risposte:


16

Usa la sostituzione dei comandi di Bash $(), -ocon grep devi anche selezionare solo la parte corrispondente:

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

Nota che anche se in questo caso riuscirai a scappare, ma dovresti sempre racchiudere la sostituzione dei comandi tra virgolette doppie in modo che la shell non esegua la divisione delle parole negli spazi bianchi (per impostazione predefinita, spazio, tab e newline, dipende dalla IFSvariabile in caso di bash).


9

A seconda di ciò che fai e non sai in anticipo su cosa pipverrà prodotto, potresti decidere di fare grepqualcosa di diverso /usr.*.

Se sai che la directory inizia con/usr (e che appare alla fine della riga di output da pip, e che /usrnon appare da nessuna parte sulla riga prima del nome della directory), allora questa è una buona scelta; La risposta di Heemayl ti dice come.

Se la ragione per cui sai che inizia /usrè che hai appena eseguito il comando e conosci la directory in cui vuoi cambiare, ti suggerisco la soluzione più semplice di eseguire il comando cd /usr/lib64/python2.7/site-packages. Questo è meno digitando anche se non si utilizza il completamento della scheda .

Altrimenti, potresti scegliere una regexp diversa a seconda di ciò che sai sull'output da analizzare. Tutte le alternative seguenti presuppongono ancora che il nome della directory appaia alla fine della riga, ma le altre ipotesi variano.

Se sai che il nome della directory è assoluto (cioè inizia con a /) e non /appare sulla riga prima del nome della directory , puoi usare lo stesso regexp della risposta di heemayl ma con /invece di /usr:

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

Questo corrisponde a /seguito da zero o più ( *) di qualsiasi carattere ( .).

Se sai che il nome della directory non contiene spazi bianchi orizzontali (senza spazi o tabulazioni) e appare alla fine della riga , puoi usare:

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

Qui ho usato un Perge regexp ( -P) perché l' \habbreviazione (for [:blank:]) rende questo testo più facile da scrivere e da leggere rispetto a un regexp ( -E) esteso equivalente . Questo corrisponde a uno o più ( +) di qualsiasi carattere in una classe di caratteri ( [ ]) che non è ( ^) uno spazio o una scheda ( \h).

Se sai che il nome della directory è immediatamente preceduto da uno inspazio bianco orizzontale (ad esempio, imbottito sia a sinistra che a destra con spazi vuoti), e che questa è l'unica occorrenza della inriga , puoi usare:

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

Questo utilizza un'asserzione look-behind positiva di larghezza zero ( \K) per abbinare uno o più caratteri ( .+) che compaiono dopo uno spazio o una scheda ( \h) ine un altro uno o più spazi o tab ( \h+), senza effettivamente includere ine gli spazi vuoti circondandolo nella partita. Le asserzioni intorno sono una caratteristica delle espressioni regolari Perl.

Anche il modello avrebbe funzionato, ma dobbiamo solo cercare uno spazio prima , indipendentemente da quanti sono presenti. Al contrario, dobbiamo abbinare tutti gli spazi vuoti dopo , altrimenti non verrebbero eliminati e verrebbero abbinati come parte del nome della directory.\h+in\h+\K.+inin\K

Se sai che il nome della directory è immediatamente preceduto dall'ultima occorrenza della riga inseguita da uno spazio bianco orizzontale , puoi usare:

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

In questo caso, l'asserzione look-behind positiva a larghezza zero stessa contiene un'asserzione look-ahead negativa a larghezza zero ( (?! )).

L' !aspetto sembra difficile da sfuggire elegantemente; il metodo che ho usato per impedirgli di innescare l' espansione della cronologia della shell prima di essere passato grepè disabilitare temporaneamente l'espansione della cronologia ( set +H) prima di eseguire il comando e riattivarlo ( set -H) in seguito. Se lo stai usando in uno script e il tuo script non contiene set -H, non è necessario farlo poiché l'espansione della cronologia è abilitata automaticamente solo quando una shell viene eseguita in modo interattivo.

Infine, nota che nessuno di questi, né la risposta di Heemayl , stanno effettivamente eseguendo il piping dell'output di grepto cd(sebbene l'output di pipsia ancora in fase di piping grep). Invece delle pipe , lo strumento appropriato per questo lavoro è la sostituzione dei comandi .


Ovviamente, se vuoi essere tecnico , la shell usa internamente una pipe per leggere l'output del comando.
Casuale 832,

@ Random832 Un buon punto: l'ho modificato leggermente in considerazione di ciò. A proposito, sai se si può fare affidamento sull'uso di tubi "sotto il cofano" nella sostituzione dei comandi? O è un dettaglio di implementazione che potrebbe potenzialmente essere fatto diversamente in una versione diversa e futura di bash? (Certo, in pratica, capisco che è il modo migliore per farlo, e quindi è improbabile che venga implementato in modo diverso.)
Eliah Kagan

1
No, non è garantito, in teoria una shell potrebbe usare un file fifo o temp con nome, anche se non c'è motivo di farlo.
Casuale 832,

Sei sicuro dell'espansione della storia? Gli unici caratteri che possono bloccarlo sono ` and '', e hai usato virgolette singole intorno all'espressione grep.
muru,

1
@muru Sì, è espanso. Neanche io l'avevo notato, ma l'ho scoperto quando l'ho provato. Il !non è citato con '-quotes, in quanto gli 'stessi -quotes sono citati. La complessità del comando rende facile prevederne gli effetti, ma apparentemente a causa dell'ordine delle espansioni ( !è in anticipo) finisce per funzionare come x=foo; echo "'$x'"(-> 'foo'). Rimozione delle esterne "-quotes causerebbe !essere '-quoted e prevenire l'espansione della cronologia, ma poi cd fallirebbe se la directory ha spazi nel suo nome.
Eliah Kagan,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.