Non puoi usare! $ Nello script?


11

Mi chiedo solo perché non funziona

#!/bin/bash 

ls /bin
ls !$

Mi aspetto di correre ls /bindue volte, ma il secondo genera errori in quanto !$non interpretato

Mi sono perso qualcosa o ho !$lavorato solo nella riga di comando?

Non sono riuscito a trovare la parte rilevante in man bash(su Mac)


9
Anche se esiste una soluzione, questo è davvero il modo migliore per ottenere questo risultato in uno script? la cronologia è disabilitata per impostazione predefinita per un motivo quando si esegue in modo non interattivo: uno script lungo invierà spam al file .bash_history. Non dire che non valeva la pena chiederlo, ma solo che se stai pensando di usarlo in uno script, è davvero il modo migliore?
flungo,

Risposte:


26

La cronologia e l' espansione della cronologia sono disabilitate per impostazione predefinita quando la shell viene eseguita in modo non interattivo.

Hai bisogno:

#!/bin/bash 

set -o history
set -o histexpand

ls /bin
ls !$

o:

SHELLOPTS=history:histexpand bash script.sh

influenzerà tutte le istanze bash che script.shpossono essere eseguite.


9
facendo attenzione a SHELLOPTS, ciò influirà su ciò bashche viene eseguito script.sh, ma anche su tutte le altre bashistanze che script.shpotrebbero eventualmente essere eseguite (come altri bashscript ...).
Stéphane Chazelas,

E non colpire qualsiasi altra bash istanza che viene eseguito lo script.
Blacklight Shining

Penso che questa risposta migliorerebbe se il commento di @ StéphaneChazelas viene modificato in esso.
Oliphaunt: ripristina Monica il

7

La cosa sana da fare sarebbe

ls /bin
ls $_

o

set ls /bin
$*
$*

o

c='ls /bin'
$c
$c

Avvertenze: vale la pena ricordare che ognuna di queste presenta alcune insidie. La soluzione $ _ cattura solo l'ultimo singolo argomento: quindi ls foo barlascerà $ _ contenente solo bar. L'uno utilizzando setsostituiranno gli argomenti ( $1, $2, ecc). E tutto ciò come scritto funzionerà, ma quando generalizzato a comandi più complessi (dove la fuga e lo spazio bianco contano), potresti incontrare alcune difficoltà. Ad esempio: ls 'foo bar'(dove l'argomento percorso singolo foo barcontiene due o più spazi o qualsiasi altro carattere di spazio) non si comporterà correttamente in nessuno di questi esempi. Una corretta evasione (eventualmente combinata con un evalcomando) o l'utilizzo al "$@"posto di $*, potrebbe essere necessaria per aggirare quei casi.


1
+1 per una risposta che è portatile e non abusa di un bashismo inteso a semplificare l'uso interattivo. (A parte questo, il desiderio di Bash di espandere in modo interattivo i punti esclamativi nella configurazione predefinita è qualcosa che trovo controintuitivo come utente di altre shell e controproducente perché mi dà sempre fastidio quando cerco di eseguire un comando di shell complicato).
mtraceur,

Anche se come scritto in questo momento, ero titubante nel dargli il +1 a causa dei problemi che probabilmente gli scripter di shell principianti avranno quando proveranno a generalizzare a comandi più complessi. Ho suggerito una modifica per aggiungere almeno un paragrafo di avvertimento che spiegasse le possibili insidie ​​di ciò.
mtraceur,

@mtraceur: non è portatile, funziona solo in bash, zsh, ksh (se due comandi non sono nella stessa riga). Lavora in dash, mksh solo quando interattivo
cuonglm

@cuongim: scusate, forse ero troppo distrattamente. Il $_modo in cui non è portatile, hai ragione. L' setapproccio funziona in un trattino non interattivo e con il ${1+"$@"}trucco (più lo zias globale alias) dovrebbe essere generale, anche se ricordo vagamente che setha una storia di non essere perfettamente portatile con alcune (vecchie?) Shell. L'approccio define-a-variabile-holding-the-command-and-then-eval-it, specialmente usando l'escaping corretto e un evalcomando reale , è completamente generalmente portatile per quanto ne so.
mtraceur,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.