Wie führe ich mehrere Befehle mit demselben Argument aus?

16

Ich frage mich, ob es möglich ist, Kettenaktionen im Ubuntu-Terminal durchzuführen, wie zum Beispiel:

action 1 on objectA . then action 2 on objectA 

ohne den Namen von objectA wiederholen zu müssen.

Beispiel:

touch file.js && openEditor "$1" 

oder etwas ähnliches.

HoCo_
quelle
Es gibt viele Möglichkeiten, dies zu tun, hängt jedoch von Ihren Bedürfnissen ab. Was ist objectA? eine Datei ? Über welche Aktionen sprechen wir?
Sergiy Kolodyazhnyy
Dank, in der Regel eine Datei effektiv, kann auch ein Ordner sein
HoCo_
3
Hier &wird der "touch" -Befehl in den Hintergrund geschickt. Wenn Sie beabsichtigten, "den Editor zu öffnen, wenn Touch erfolgreich war", dann möchten Sie &&stattdessen
Glenn Jackman
Warum stößt du diesen Beitrag? Sie haben bereits viele Antworten erhalten und sogar eine angenommen.
muru

Antworten:

27

Mit der Bash- History-Erweiterung können Sie auf das n-te Wort der aktuellen Befehlszeile verweisen, indem Sie !#:nz

$ 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
Stahlfahrer
quelle
Darf ich fragen, welche Bash-Version Sie verwenden?
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy das istGNU bash, version 4.3.48(1)-release
steeldriver
5
Sie können auch eine Reihe von Wörterntouch foo bar && ls -l !#:1-2
angeben
1
@HoCo_ dem !Charakter führt eine Geschichte Expansion Ausdruck wenn Sie in einer interaktiven Shell - es ist für on-the-fly - Befehlszeile Manipulation wie Sie schreiben gemeint ist, und ist deaktiviert innen nicht-interaktive Skripte
steeldriver
1
@HoCo_ In einem Skript solltest du wissen, was das Argument ist, also könntest du es zum Beispiel einfach tunarg1=file.js; touch "$arg1" && openEditor "$arg1"
steeldriver
12

Es gibt eine praktische Verknüpfung für einen allgemeinen Anwendungsfall. In deinem Beispiel machst du:

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

Im zweiten Befehl besteht der Trick darin, openEditor(mit einem Leerzeichen danach) gefolgt von Alt+ zu schreiben .. Dies fügt das letzte Argument des letzten Befehls ein file.js. (Wenn es Altaus irgendeinem Grund nicht funktioniert , Escsollte es auch funktionieren.)

Da das "Objekt" häufig das letzte Argument des vorherigen Befehls ist, kann es häufig verwendet werden. Es ist leicht zu merken und lässt sich schnell in Ihre intuitiv zu verwendenden Shell-Verknüpfungen integrieren.

Es gibt eine ganze Reihe von Dingen, die Sie damit tun können. Hier ist ein ausführlicher Artikel über die Möglichkeiten: /programming/4009412/how-to-use-arguments-from-previous-command .

Als Bonus funktioniert dies nicht nur in Bash, sondern in allen Programmen, die libreadline für die Verarbeitung von Kommandozeilen-Eingaben verwenden.

Sebastian Stark
quelle
2
Sie können dies mit einem kombinieren stelliges Argument , zB das zweite Argument halten zu bekommen Altund drücken 2.(oder Esc, 2, Esc, .), die zweite zum letzten Argument Presse zu bekommen Alt+ -, Typ 2und drücken Sie Alt+ .(oder Esc, -2, Esc, .).
Dessert
@dessert Was ist, wenn ich mehr als eines der Argumente ausführen möchte? ZB ich laufe echo 1 2 3 4dann ich will 2und 3für den nächsten Befehl
wjandrea
@ Dessert Fand es selbst! Sie müssen nur noch etwas dazwischen eingeben, z. B. ein Leerzeichen. Um sie zu verketten, ist es am einfachsten, ein Leerzeichen und dann ein Backspace einzugeben.
wjandrea
1
@wjandrea halten , Altund die Art 2., drücken Sie die Leertaste, halten Altund Typ 3.- wenn Sie einen Bereich, Nutzung Geschichte Expansion wollen: !!:2-3.
Dessert
9

Was den Standard interaktiv Shell bashund Scripting Shell dashgeht, können Sie $_erinnern letztes Argument des letzten Befehls .

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

csh und tcsh haben Verlaufsreferenzen, insbesondere für das letzte Wort des Befehls, das Sie verwenden können !$, und für einzelne Argumente !:<index>:

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

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

Im Allgemeinen ist es einfach besser, objectAeiner Variablen zuzuweisen, was auch immer ist , und es in mehreren Befehlen, Schleifen usw. zu verwenden. Alternativ kann eine Funktion eine Wahl sein:

$ foo(){ echo "$@"; stat --print="%F\n" "$@";}
$ foo testdir
testdir
directory
Sergiy Kolodyazhnyy
quelle
1
Ich möchte nur darauf hinweisen, dass dies $_etwas anders funktioniert, als !#:nwenn letzteres erweitert wird, bevor der Befehl im Verlauf gespeichert wird. Wenn Sie also in die Historie zurückgehen, wird der Befehl mit $_while !#:nimmer noch durch seinen tatsächlichen Wert ersetzt. Beide haben ihre Vor- und Nachteile.
Dan
3
Auch sollte wie üblich $_zitiert werden, da es sonst wie alles andere gespalten und globbed wird. (Wir sehen es hier einfach nicht, da echodie Argumente mit einem Leerzeichen verbunden sind.) Aber zB touch "hello there"; ls -l $_ funktioniert nicht.
Ilkkachu
1
@Dan Ich denke, der größte Vorteil $_ist, dass es portabel ist. Immerhin !#:nist bash-spezifisch.
Sergiy Kolodyazhnyy
3

Ich würde gegen den in der Antwort von steeldriver angegebenen Verlaufsansatz empfehlen . Dies hängt vom globalen Staat ab, der immer brüchig ist.

Besser ist es, die Schleife über alle benötigten Befehle mit einer geeigneten Variablen im Voraus zu durchlaufen:

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

Was im Allgemeinen ein kleines Problem ist, ist, dass Bash nicht abbricht, wenn es einen Fehler gibt, dh dies verhält sich tatsächlich so, als touch foo.txt; gedit foo.txtwürde man mit verketten &&. Um sicher zu gehen, können Sie Folgendes hinzufügen break:

$ for c in touch gedit; do $c foo.txt || break; done
links herum
quelle
1

Beim Kochen eines Einzeilers ordne ich meine wiederholte Sache manchmal einer Shell-Variablen zu, die ich im Befehl mehrmals verwende. Ich kann es aufrufen und bearbeiten, um ein anderes Argument mit Aufwärtspfeil, Strg + a, Strg + Rechtspfeil zu verwenden, um den Cursor in die Nähe des zu bringen t=.

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

Beachten Sie, dass dies das Anheften einer Erweiterung oder einer Variation des Namens erleichtert.

Beachten Sie auch, dass ich ;nach der Variablenzuweisung eine benötige , da diese var=value cmdnur als Umgebungsvariable für diesen Befehl festgelegt wird und sich nicht auf den Shell-Kontext auswirkt.

Peter Cordes
quelle