Come utilizzare più argomenti per awk con uno shebang (cioè #!)?
Domanda
Mi piacerebbe eseguire un href="http://en.wikipedia.org/wiki/AWK#Versions_and_implementations" rel="noreferrer"> gawk sceneggiatura --re-interval utilizzando una shebang. L'approccio "naive" della
#!/usr/bin/gawk --re-interval -f
... awk script goes here
non funziona, dal momento che gawk viene chiamato con la prima "--re-interval -f"
argomento (non a spacco intorno gli spazi bianchi), che non capisce. C'è una soluzione per questo?
Naturalmente è possibile o non chiamare gawk direttamente, ma avvolgerlo in uno script di shell che divide il primo argomento, o fare uno script di shell che quindi chiama gawk e mettere lo script in un altro file, ma mi chiedevo se ci fosse qualche modo per fare questo all'interno di un unico file.
Il comportamento della faccenda linee differisce da sistema a sistema - almeno in Cygwin non è così dividere gli argomenti con spazi bianchi. Ho appena interessa come farlo su un sistema che si comporta come quello; lo script non è destinata ad essere portatile.
Soluzione
Questo sembra funzionare per me con (g) awk.
#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
# The real awk program starts here
{ print $0 }
Si noti la #!
corre /bin/sh
, quindi questo script viene prima interpretata come uno script di shell.
Inizialmente, ho semplicemente provato "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
, ma awk considerato che come un comando e stampato fuori ogni linea di input incondizionatamente. È per questo che ho messo nel arbitrary_long_name==0
- si suppone a fallire tutto il tempo. Si potrebbe sostituirlo con qualche stringa senza senso. In sostanza, ero alla ricerca di un falso-condizione in awk che non influenzare negativamente lo script di shell.
Nello script shell, il arbitrary_long_name==0
definisce una variabile denominata arbitrary_long_name
e imposta uguale a =0
.
Altri suggerimenti
La linea shebang non è mai stata specificata come parte di POSIX, SUS, LSB o qualsiasi altra specifica. Per quanto ne so, si è nemmeno stata adeguatamente documentata.
V'è un consenso di massima su ciò che fa: prendere tutto tra il !
e \n
e exec
esso. Il presupposto è che tutto tra il !
ed il \n
è un percorso assoluto completo per l'interprete. Non c'è consenso su ciò che accade se contiene spazi bianchi.
- Alcuni sistemi operativi semplicemente trattare la cosa intera come il percorso. Dopo tutto, nella maggior parte dei sistemi operativi, spazi o trattini sono legali in un percorso.
- Alcuni sistemi operativi divisi in spazi e trattano la prima parte, il percorso per l'interprete e il resto come singoli argomenti.
- Alcuni sistemi operativi divisi al prima spazi e trattare la parte anteriore come il percorso per l'interpeter e il resto come un solo argomento (che è quello che si sta vedendo ).
- Alcuni addirittura non supportano linee Shebang a tutti .
Per fortuna, 1. e 4. sembra che sia morto, ma 3. è abbastanza diffusa, in modo semplicemente non si può contare sul fatto di poter passare più di un argomento.
E dal momento che la posizione dei comandi è, inoltre, non specificato in POSIX o SUS, in genere si usa up che singolo argomento passando dell'eseguibile nome per env
in modo che è lattina determinare la posizione del file eseguibile; per esempio:.
#!/usr/bin/env gawk
[Ovviamente, questa ancora assume una particolare percorso per env
, ma ci sono solo pochi sistemi in cui vive in /bin
, quindi questo è generalmente sicura. La posizione di env
è molto più standardizzato rispetto alla posizione del gawk
o peggio ancora qualcosa di simile python
o ruby
o spidermonkey
.]
Il che significa che non si può effettivamente usare qualsiasi a tutti .
mi sono imbattuto lo stesso problema, senza soluzione apparente a causa del modo in cui gli spazi bianchi sono trattati in uno shebang (almeno su Linux).
Tuttavia, si può passare diverse opzioni in una baracca, nella misura in cui sono opzioni brevi e possono essere concatenati (il modo in cui GNU).
Per esempio, non si può avere
#!/usr/bin/foo -i -f
, ma si può avere
#!/usr/bin/foo -if
Ovviamente, che funziona solo quando le opzioni sono equivalenti a breve e prendere senza argomenti.
Sotto Cygwin e Linux tutto dopo il percorso della baracca viene analizzato per il programma come un argomento.
E 'possibile incidere intorno a questo utilizzando un altro script awk
all'interno della baracca:
#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
Questo eseguirà {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
in awk.
E questo eseguirà /usr/bin/gawk --re-interval -f path/to/your/script.awk
nei vostri sistemi shell.
Anche se non è esattamente portatile, a partire da coreutils 8.30 e in base alla relativa documentazione si sarà in grado di utilizzare:
#!/usr/bin/env -S command arg1 arg2 ...
Quindi, dato:
$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too
si otterrà:
% ./test.sh
$0 is '/usr/local/bin/showargs'
$1 is 'here'
$2 is 'is another'
$3 is 'long'
$4 is 'arg'
$5 is '-e'
$6 is 'this and that '
$7 is 'too'
$8 is './test.sh'
e nel caso in cui siete curiosi showargs
è:
#!/usr/bin/env sh
echo "\$0 is '$0'"
i=1
for arg in "$@"; do
echo "\$$i is '$arg'"
i=$((i+1))
done
qui .
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''
Il guscio sopra shebang trucco è più portabile di /usr/bin/env
.
Nel manuale gawk (http://www.gnu.org/manual/gawk/gawk.html), alla fine della sezione 1.14 Si raccomanda di utilizzare solo un unico argomento quando si esegue gawk da una linea di shebang. Si dice che il sistema operativo tratterà tutto dopo il percorso di gawk come un unico argomento. Forse c'è un altro modo per specificare l'opzione --re-interval
? Forse il vostro script può fare riferimento la shell nella linea shebang, gawk
eseguito come un comando e includere il testo del vostro script come un "here document".
Perché non usare bash
e gawk
per sé, per saltare la baracca passato, letto la sceneggiatura, e passarla come un file a una seconda istanza di gawk [--with-whatever-number-of-params-you-need]
?
#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' $0 )
exit
{
print "Program body goes here"
print $1
}
(- lo stesso si potrebbe naturalmente anche essere realizzato con per esempio sed
o tail
, ma penso che ci sia un certo tipo di bellezza dipendente solo da bash
e gawk
stesso;)
Solo per divertimento:. V'è la seguente soluzione abbastanza strano che reindirizza stdin e il programma attraverso descrittori di file 3 e 4. Si potrebbe anche creare un file temporaneo per lo script
#!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print "HALLO"}
{print \$1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3
Una cosa è fastidiosa di questo:. Il guscio fa di espansione variabile sullo script, quindi bisogna citare ogni $ (come fatto nella seconda riga dello script) e, probabilmente, più di questo
Per una soluzione portatile, uso awk
piuttosto che gawk
, invocare la Bourne shell standard (/bin/sh
) con la faccenda, e invocare awk
direttamente, passando il programma sulla riga di comando come qui documentare piuttosto che attraverso stdin:
#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF
Nota: non -f
argomento per awk
. Che lascia stdin
disponibile per awk
per leggere l'input da. Supponendo di avere gawk
installato e sul PATH
, che consente di ottenere tutto quello che penso si stavano cercando di fare con il tuo esempio originale (supponendo che voleva che il contenuto del file di essere lo script awk e non l'ingresso, che a mio avviso il tuo approccio faccenda avrebbe trattato come).