Comment exécuter plusieurs commandes en utilisant le même argument?


16

Je me demande s'il est possible de faire des actions en chaîne dans le terminal Ubuntu comme:

action 1 on objectA . then action 2 on objectA 

sans avoir à répéter le nom de objectA.

Exemple:

touch file.js && openEditor "$1" 

ou quelque chose comme ça.


Il existe de nombreuses façons de le faire, mais cela dépend de vos besoins. Qu'est-ce que objectA? un fichier ? De quelles actions parlons-nous?
Sergiy Kolodyazhnyy

merci, généralement un fichier efficace, peut également être un dossier
HoCo_

3
Ici, &enverra la commande "touch" en arrière-plan. Si vous aviez l'intention "d'ouvrir l'éditeur si le toucher a réussi", alors vous voulez &&plutôt
glenn jackman

Pourquoi cognez-vous ce post? Vous avez déjà obtenu de nombreuses réponses et vous en avez même accepté une.
muru

Réponses:


27

Avec bash History Expansion , vous pouvez vous référer au nième mot de la ligne de commande actuelle en utilisant !#:npar exemple

$ touch foobar && ls -l !#:1
touch foobar && ls -l foobar
-rw-rw---- 1 steeldriver steeldriver 0 Jun 20 14:54 foobar

$ touch foo bar && ls -l !#:2
touch foo bar && ls -l bar
-rw-rw-r-- 1 steeldriver steeldriver 12 Jun 20 14:58 bar

Puis-je demander quelle version bash vous utilisez?
Sergiy Kolodyazhnyy

@SergiyKolodyazhnyy this isGNU bash, version 4.3.48(1)-release
steeldriver

5
vous pouvez également désigner une gamme de mots :touch foo bar && ls -l !#:1-2
glenn jackman

1
@HoCo_ le !personnage introduit une expression d'expansion de l'historique lorsque vous êtes dans un shell interactif - il est destiné à la manipulation en ligne de commande à la volée pendant que vous tapez, et est désactivé dans les scripts non interactifs
steeldriver

1
@HoCo_ dans un script, vous devez savoir ce que l'argument est à l'avance - donc par exemple, vous pouvez simplement le fairearg1=file.js; touch "$arg1" && openEditor "$arg1"
steeldriver

12

Il existe un raccourci pratique pour un cas d'utilisation courant. Dans votre exemple, vous faites:

$ touch file.js
$ openEditor <alt>+<.>

Dans la deuxième commande, l'astuce consiste à écrire openEditor(avec un espace après) suivi de Alt+ .. Cela insérera le dernier argument de la dernière commande, qui est file.js. (Si cela ne fonctionne pas Altpour une raison quelconque, Escdevrait également fonctionner.)

Puisque souvent "l'objet" est en effet le dernier argument de la commande précédente, cela peut être utilisé fréquemment. Il est facile à retenir et s'intégrera rapidement dans votre ensemble de raccourcis shell intuitivement utilisés.

Il y a tout un tas de choses que vous pouvez faire avec ceci, voici un article détaillé sur les possibilités: /programming/4009412/how-to-use-arguments-from-previous-command .

En prime, cela fonctionnera non seulement dans bash mais dans tous les programmes qui utilisent libreadline pour traiter l'entrée de ligne de commande.


2
Vous pouvez combiner cela avec un argument chiffres , par exemple pour obtenir la deuxième prise d'arguments Altet appuyez sur 2.(ou Esc, 2, Esc, .), pour obtenir le deuxième à la dernière presse l' argument Alt+ -, le type 2et appuyez sur Alt+ .(ou Esc, -2, Esc, .).
dessert

@dessert Et si je cours, je veux plusieurs arguments? Par exemple, je cours echo 1 2 3 4alors je veux 2et 3pour la prochaine commande
wjandrea

@dessert Je l'ai trouvé moi-même! Vous avez juste besoin de taper autre chose entre eux, comme un espace. Pour les concaténer, le plus simple est de taper un espace puis de revenir en arrière.
wjandrea

1
@wjandrea attente Altet le type 2., appuyez sur la barre d' espace, attente Altet le type 3.- si vous voulez une plage, utilisez l' expansion de l' histoire: !!:2-3.
dessert

9

En ce qui concerne le shell interactif par défaut bashet le shell de script dash, vous pouvez utiliser $_pour rappeler le dernier argument de la dernière commande .

$ echo "Hello World"; echo same "$_"
Hello World
same Hello World

csh et tcsh ont des références d'historique, spécifiquement pour le dernier mot de la commande, vous pouvez utiliser !$, et pour des arguments individuels - !:<index>:

~% echo foo bar
foo bar
~% echo !$
echo bar
bar

% echo bar baz
bar baz
% echo !:1
echo bar
bar

En général, il est préférable d'affecter ce qui est objectAà une variable et de l'utiliser dans plusieurs commandes, boucles, etc. Alternativement, une fonction peut être un choix:

$ foo(){ echo "$@"; stat --print="%F\n" "$@";}
$ foo testdir
testdir
directory

1
Je voudrais juste souligner que cela $_fonctionne légèrement différemment que !#:nlorsque ce dernier est développé avant d'enregistrer la commande dans l'historique. Donc, remonter dans l'histoire afficherait toujours la commande avec $_while !#:naurait été remplacé par sa valeur réelle. Ils ont tous deux leur pour et contre.
Dan

3
De plus, comme d'habitude, $_il convient de le citer, sinon il sera divisé et globulé comme tout le reste. (Nous ne le voyons pas ici car il echojoint ses arguments à un seul espace.) Mais par exemple touch "hello there"; ls -l $_ , ne fonctionnera pas.
ilkkachu

1
@ Dan, je pense que le plus grand pro $_est qu'il est portable. Après tout, !#:nest spécifique à bash.
Sergiy Kolodyazhnyy

3

Je recommanderais contre l'approche historique donnée dans la réponse de Steeldriver . Cela dépend de l'état global, qui est toujours fragile.

Le mieux est de boucler en amont toutes les commandes nécessaires, en utilisant une variable appropriée:

$ for c in touch gedit; do $c foo.txt; done

Ce qui est un peu un problème en général, c'est que Bash n'interrompt pas en cas d'échec, c'est-à-dire que cela se comporte comme touch foo.txt; gedit foo.txtau lieu d'être enchaîné avec &&. Donc, pour être sûr, vous pouvez ajouter un break:

$ for c in touch gedit; do $c foo.txt || break; done

1

Lors de la cuisson d'un one-liner, j'affecte parfois ma chose répétée à une variable shell que j'utilise plusieurs fois dans la commande. Je peux le rappeler et le modifier pour utiliser un argument différent avec la flèche vers le haut, contrôle + a, contrôle + flèche droite pour obtenir le curseur près du t=.

t=testloop; asm-link -d "$t.asm" && perf stat -r2 ./"$t"

Notez que cela facilite le clouage sur une extension ou une variation du nom.

Notez également que j'ai besoin d'un ;après l'affectation de variable, car var=value cmddéfinit simplement cela comme une variable d'environnement pour cette commande, et n'affecte pas le contexte du shell.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.