Jak wykonać wiele poleceń przy użyciu tego samego argumentu?

16

Zastanawiam się, czy można wykonać akcje łańcuchowe w terminalu Ubuntu, takie jak:

action 1 on objectA . then action 2 on objectA 

bez konieczności powtarzania nazwy obiektu A.

Przykład:

touch file.js && openEditor "$1" 

czy jakoś tak.

HoCo_
źródło
Jest na to wiele sposobów, ale zależy to od twoich potrzeb. Co to jest obiekt A? plik ? O jakich działaniach mówimy?
Sergiy Kolodyazhnyy
dzięki, zwykle plik skutecznie, może być również folderem
HoCo_
3
Tutaj &wyśle ​​polecenie „dotknij” w tło. Jeśli chciałeś „otworzyć edytor, jeśli dotyk się udał”, to &&zamiast tego chcesz
glenn jackman
Dlaczego natrafiasz na ten post? Masz już wiele odpowiedzi, a nawet jedną zaakceptowałeś.
muru

Odpowiedzi:

27

Dzięki bash History Expansion możesz odwoływać się do n-tego słowa bieżącego wiersza poleceń, używając !#:nnp

$ 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
steeldriver
źródło
Czy mogę zapytać, której wersji bash używasz?
Sergiy Kolodyazhnyy
@SergiyKolodyazhnyy this isGNU bash, version 4.3.48(1)-release
steeldriver
5
możesz także wyznaczyć szereg słów :touch foo bar && ls -l !#:1-2
glenn jackman
1
@HoCo_ !postać wprowadza wyrażenie rozszerzające historię, gdy jesteś w interaktywnej powłoce - jest przeznaczona do manipulowania w linii poleceń podczas pisania i jest wyłączona w skryptach
nieinteraktywnych
1
@HoCo_ w skrypcie powinieneś wiedzieć, jaki argument jest przed czasem - więc na przykład możesz po prostu zrobićarg1=file.js; touch "$arg1" && openEditor "$arg1"
steeldriver
12

Istnieje przydatny skrót do typowego przypadku użycia. W twoim przykładzie robisz:

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

W drugim poleceniu polega na tym, aby pisać openEditor(ze spacją po nim), a następnie Alt+ .. Spowoduje to wstawienie ostatniego argumentu ostatniego polecenia, którym jest file.js. (Jeśli z Altjakiegoś powodu to nie działa , Escpowinno również działać.)

Ponieważ często „obiekt” jest rzeczywiście ostatnim argumentem poprzedniego polecenia, można go często używać. Jest łatwy do zapamiętania i szybko zintegruje się z zestawem intuicyjnie używanych skrótów powłoki.

Jest wiele rzeczy, które możesz z tym zrobić, oto szczegółowy artykuł na temat możliwości: /programming/4009412/how-to-use-arguments-from-previous-command .

Jako bonus działa to nie tylko w bash, ale we wszystkich programach, które używają libreadline do przetwarzania danych z wiersza poleceń.

Sebastian Stark
źródło
2
Można połączyć to z cyfrowym argumentu , np dostać drugą trzymać argumentów Alti naciśnij 2.(lub Esc, 2, Esc, .), aby uzyskać od drugiego do ostatniego argumentu prasowej Alt+ -, typ 2i naciśnij Alt+ .(lub Esc, -2, Esc, .).
deser
@dessert Co się stanie, jeśli uruchomię, chcę więcej niż jeden argument? Np. echo 1 2 3 423
Uruchamiam,
@dessert Znalazłem to sam! Wystarczy wpisać między nimi coś innego, na przykład spację. Aby je połączyć, najprostszym sposobem jest wpisanie spacji, a następnie cofnięcie.
wjandrea
1
@wjandrea hold Alti rodzaj 2., naciśnij klawisz spacji, wstrzymywania Alti typ 3.- jeśli chcesz zakres, wykorzystanie Historia ekspansji: !!:2-3.
deser
9

Jeśli chodzi o domyślną powłokę interaktywną bashi powłokę skryptową dash, możesz użyć $_do przywołania ostatniego argumentu ostatniego polecenia .

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

csh i tcsh mają odwołania do historii, szczególnie dla ostatniego słowa polecenia, którego możesz użyć !$, a dla poszczególnych argumentów - !:<index>:

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

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

Ogólnie rzecz biorąc, po prostu lepiej przypisać cokolwiek objectAdo zmiennej i użyć go w wielu poleceniach, pętlach itp. Alternatywnie, funkcja może być wyborem:

$ foo(){ echo "$@"; stat --print="%F\n" "$@";}
$ foo testdir
testdir
directory
Sergiy Kolodyazhnyy
źródło
1
Chciałbym tylko zaznaczyć, że $_działa nieco inaczej niż !#:nto ostatnie, które jest rozwijane przed zapisaniem polecenia w historii. Wracając do historii, nadal pokazywałoby to polecenie, a $_czas !#:nzostałby zastąpiony jego rzeczywistą wartością. Oba mają swoje zalety i wady.
Dan
3
Ponadto, jak zwykle, $_należy zacytować, ponieważ w przeciwnym razie zostanie podzielony i globowany jak wszystko inne. (Po prostu tego tutaj nie widzimy, ponieważ echołączy swoje argumenty z pojedynczą spacją.) Ale np. touch "hello there"; ls -l $_ Nie będzie działać.
ilkkachu
1
@ Dan Myślę, że największym profesjonalistą $_jest to, że jest przenośny. W końcu !#:njest specyficzne dla basha.
Sergiy Kolodyazhnyy
3

Odradzałbym podejście historyczne podane w odpowiedzi steeldrivera . Zależy to od stanu globalnego, który jest zawsze kruchy.

Lepiej jest zapętlić z góry wszystkie potrzebne polecenia, używając odpowiedniej zmiennej:

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

Generalnie problemem jest to, że Bash nie przerywa działania, gdy wystąpi awaria, tzn. Zachowuje się tak, jak touch foo.txt; gedit foo.txtzamiast łączenia w łańcuch &&. Aby być bezpiecznym, możesz dodać break:

$ for c in touch gedit; do $c foo.txt || break; done
po lewej stronie
źródło
1

Podczas gotowania jednego linijki czasami przypisuję powtarzaną rzecz do zmiennej powłoki, której używam wielokrotnie w poleceniu. Mogę przywołać i edytować go, aby użyć innego argumentu ze strzałką w górę, control + a, control + strzałka w prawo, aby zbliżyć kursor do t=.

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

Pamiętaj, że ułatwia to dodanie rozszerzenia lub zmiany nazwy.

Zauważ też, że potrzebuję ;po przypisaniu zmiennej, ponieważ var=value cmdpo prostu ustawia to jako zmienną środowiskową dla tego polecenia i nie wpływa na kontekst powłoki.

Peter Cordes
źródło