Comment utiliser la sortie grep comme chemin pour le cd?

9

Comment puis-je diriger la grepsortie comme argument vers la cdcommande?

Par exemple:

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

Ici /usr/lib64/python2.7/site-packagesest mis en évidence et je veux passer cette chaîne à cd.

micgeronimo
la source

Réponses:

16

Utilisez la substitution de commandes de Bash $(), vous avez également besoin -oavec grep de ne sélectionner que la partie correspondante:

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

Notez que bien que vous vous en sortiriez dans ce cas, mais vous devriez toujours entourer la substitution de commandes avec des guillemets doubles afin que le shell n'effectue pas de division des mots sur les espaces blancs (par défaut, l'espace, la tabulation et la nouvelle ligne, dépendent de la IFSvariable en cas de bash).

heemayl
la source
9

Selon ce que vous faites et ne savez pas à l'avance ce qui pipva sortir, vous pouvez décider de faire grepautre chose que /usr.*.

Si vous savez que le répertoire commence par/usr (et qu'il apparaît à la fin de la ligne de sortie de pip, et qu'il /usrn'apparaît nulle part sur la ligne avant le nom du répertoire), alors c'est un bon choix; la réponse de heemayl vous explique comment.

Si la raison pour laquelle vous savez que cela commence par le /usrfait que vous venez d'exécuter la commande et que vous connaissez le répertoire dans lequel vous souhaitez changer, je suggère la solution la plus simple pour exécuter la commande cd /usr/lib64/python2.7/site-packages. C'est moins de frappe même si vous n'utilisez pas la complétion de tabulation .

Sinon, vous pouvez choisir une expression rationnelle différente en fonction de ce que vous savez sur la sortie analysée. Toutes les alternatives ci-dessous supposent toujours que le nom du répertoire apparaît à la fin de la ligne, mais les autres hypothèses varient.

Si vous savez que le nom du répertoire est absolu (c'est-à-dire qu'il commence par un /) et qu'aucun /n'apparaît sur la ligne avant le nom du répertoire , vous pouvez utiliser la même expression rationnelle que dans la réponse de heemayl mais avec /au lieu de /usr:

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

Cela correspond à un /suivi de zéro ou plus ( *) de n'importe quel caractère ( .).

Si vous savez que le nom du répertoire ne contient aucun espace horizontal (aucun espace ni tabulation) et apparaît à la fin de la ligne , vous pouvez utiliser:

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

Ici, j'ai utilisé une expression rationnelle Perl ( -P) parce que l' \habréviation (pour [:blank:]) rend cela plus facile à taper et à lire qu'une expression régulière étendue équivalente ( -E). Cela correspond à un ou plusieurs ( +) de n'importe quel caractère d'une classe de caractères ( [ ]) qui n'est pas ( ^) un espace ou une tabulation ( \h).

Si vous savez que le nom du répertoire est immédiatement précédé d' inun espace blanc horizontal (c.-à-d. Rempli à la fois à gauche et à droite avec des espaces) et que c'est la seule occurrence de ce type insur la ligne , vous pouvez utiliser:

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

Cela utilise une assertion de regard positif de largeur nulle ( \K) pour faire correspondre un ou plusieurs caractères ( .+) qui apparaissent après un espace ou une tabulation ( \h) in, et un ou plusieurs autres espaces ou tabulations ( \h+), sans réellement inclure inet les espaces vides. l'entourant dans le match. Les assertions de regard sont une caractéristique des expressions régulières de Perl.

Le modèle aurait également fonctionné, mais nous n'avons besoin que de rechercher un blanc avant , quel que soit le nombre. En revanche, nous devons faire correspondre tous les blancs après , sinon ils ne seraient pas supprimés et ils seraient mis en correspondance dans le nom du répertoire.\h+in\h+\K.+inin\K

Si vous savez que le nom du répertoire est immédiatement précédé de la dernière occurrence de la ligne insuivi d'un espace horizontal , vous pouvez utiliser:

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

Là, l'assertion de recherche positive de largeur nulle elle-même contient une assertion de recherche négative de largeur nulle ( (?! )).

Le !apparaît de manière à être difficile à échapper avec élégance; la méthode que j'ai utilisée pour l'empêcher de déclencher l'expansion de l'historique du shell avant d'être transmise grepest de désactiver temporairement l'expansion de l'historique ( set +H) avant d'exécuter la commande et de la réactiver ( set -H) par la suite. Si vous l'utilisez dans un script et que votre script n'en contient pas set -H, vous n'avez pas besoin de le faire car l'expansion de l'historique n'est activée automatiquement que lorsqu'un shell s'exécute de manière interactive.

Enfin, notez qu'aucun de ceux-ci, ni la réponse de heemayl , ne dirigent réellement la sortie de grepvers cd(bien que la sortie de pipsoit toujours dirigée vers grep). Plutôt que des tuyaux , l'outil approprié pour ce travail est la substitution de commandes .

Eliah Kagan
la source
Bien sûr, si vous voulez devenir technique , le shell utilise un tube en interne pour lire la sortie de la commande.
Random832
@ Random832 Bon point - j'ai édité légèrement en tenant compte de cela. Au fait, savez-vous si l'utilisation de tuyaux "sous le capot" dans la substitution de commande peut être invoquée? Ou s'agit-il d'un détail d'implémentation qui pourrait potentiellement être fait différemment dans une future version différente de bash? (Bien sûr, dans la pratique, je comprends que c'est la meilleure façon de le faire, et donc il est peu probable qu'il soit mis en œuvre différemment.)
Eliah Kagan
1
Non, ce n'est pas garanti, en théorie, un shell pourrait utiliser un fichier nommé fifo ou temp, bien qu'il n'y ait aucune raison de le faire.
Random832
Êtes-vous sûr de l'extension de l'histoire? Les seuls caractères qui peuvent le bloquer sont ` and '', et vous avez utilisé des guillemets simples autour de l'expression grep.
muru
1
@muru Oui, il est étendu. Je ne l'avais pas remarqué non plus, mais je l'ai découvert lorsque je l'ai testé. Le !il n'est pas cité avec '-quotes, car les '-quotes sont eux-mêmes cités. La complexité de la commande facilite la mauvaise estimation de son effet, mais apparemment en raison de l'ordre des extensions ( !est précoce), il finit par fonctionner comme x=foo; echo "'$x'"(-> 'foo'). La suppression des "guillemets externes entraînerait !un 'guillemet et empêcherait l'expansion de l'historique, mais cd échouerait alors si le répertoire avait un espace dans son nom.
Eliah Kagan du