Nie możesz użyć! $ W skrypcie?

11

Zastanawiam się, dlaczego to nie działa

#!/bin/bash 

ls /bin
ls !$

Spodziewam się uruchomić ls /bindwa razy, ale drugi powoduje błędy, których !$nie interpretowano

Coś przeoczyłem lub !$pracowałem tylko w linii poleceń?

Nie mogłem znaleźć odpowiedniej części w man bash(na Macu)

stokrotka
źródło
9
Chociaż istnieje rozwiązanie, czy to naprawdę najlepszy sposób na osiągnięcie tego w skrypcie? historia jest domyślnie wyłączona z tego powodu, że nie uruchamiasz się interaktywnie - długi skrypt będzie spamował plik .bash_history. Nie mówię, że nie warto o to pytać, ale po prostu, jeśli myślisz o użyciu tego w skrypcie, czy to naprawdę najlepszy sposób?
flungo

Odpowiedzi:

26

Historia i ekspansja historii są domyślnie wyłączone, gdy powłoka działa nieinteraktywnie.

Potrzebujesz:

#!/bin/bash 

set -o history
set -o histexpand

ls /bin
ls !$

lub:

SHELLOPTS=history:histexpand bash script.sh

wpłynie to na wszystkie script.shuruchamiane instancje bash .

Cuonglm
źródło
9
Ostrożnie z SHELLOPTS, wpłynie to na to, bashże działa script.sh, ale także na wszystkie inne bashinstancje, które script.shmogą ostatecznie zostać uruchomione (podobnie jak inne bashskrypty ...).
Stéphane Chazelas,
I nie wpłynie to na żadną inną bash instancję, która uruchamia twój skrypt.
Blacklight Shining
Myślę, że ta odpowiedź poprawiłaby się, gdyby komentarz @ StéphaneChazelas został w niej edytowany.
Oliphaunt - przywróć Monikę
7

Byłoby rozsądne

ls /bin
ls $_

lub

set ls /bin
$*
$*

lub

c='ls /bin'
$c
$c

Ostrzeżenia: warto pamiętać, że każdy z nich wiąże się z pewnymi pułapkami. Rozwiązanie $ _ przechwytuje tylko ostatni pojedynczy argument: więc ls foo barpozostawi $ _ zawierający just bar. Jedna z użyciem setzastępują argumenty ( $1, $2itp). Wszystko to, jak napisano, zadziała, ale po uogólnieniu na bardziej złożone polecenia (gdzie znaczenie ma znak ucieczki i spacja), możesz napotkać pewne trudności. Na przykład: ls 'foo bar'(gdy argument pojedynczej ścieżki foo barzawiera dwie lub więcej spacji lub dowolne inne znaki spacji) nie będzie działał poprawnie w żadnym z tych przykładów. W celu obejścia tych przypadków może być konieczne prawidłowe ucieczkę (ewentualnie w połączeniu z evalpoleceniem) lub użycie "$@"zamiast $*.

Steven Penny
źródło
1
+1 za odpowiedź, która jest przenośna i nie nadużywa bashizmu mającego na celu ułatwienie interaktywnego korzystania. (Nawiasem mówiąc, chęć basha do interaktywnego rozwijania wykrzykników w domyślnej konfiguracji jest dla mnie sprzeczna z intuicją jako użytkownik innych powłok i przynosi efekt przeciwny do zamierzonego, ponieważ zawsze mnie to psuje, gdy próbuję wykonać skomplikowane polecenie powłoki).
mtraceur
Chociaż, jak napisano w tej chwili, wahałem się, czy dać mu +1 ze względu na problemy, które prawdopodobnie będą mieli początkujący skrypty powłoki, próbując uogólnić to na bardziej złożone polecenia. Zasugerowałem edycję, aby przynajmniej dodać akapit z zastrzeżeniem wyjaśniający możliwe pułapki.
mtraceur
@mtraceur: nie jest przenośny, działa tylko w bash, zsh, ksh (jeśli dwa polecenia nie są w tej samej linii). Pracuj w desce rozdzielczej, mksh tylko w trybie interaktywnym
cuonglm
@cuongim: Przepraszam, być może byłem zbyt nieostrożnie ogólny. $_Sposób nie jest przenośny, masz rację. setPodejście działa w nieinterakcyjnym kreską iz ${1+"$@"}(Plus zsh globalny alias) sztuczki powinny być ogólne, choć niejasno pamiętać, że setma historię nie będąc doskonale przenośny z niektórych (?) Starych powłok. Podejście „definiuj zmienne trzymanie polecenia-a-następnie-ewaluuj-to”, zwłaszcza przy użyciu właściwego ucieczki i rzeczywistego evalpolecenia, jest całkowicie przenośne, o ile mi wiadomo.
mtraceur