Wie mehrere Argumente für awk mit einem shebang verwenden (das heißt #!)?
Frage
würde Ich mag eine gaffen Skript mit --re-interval
mit einem shebang auszuführen. Der "naive" Ansatz von
#!/usr/bin/gawk --re-interval -f
... awk script goes here
nicht funktioniert, da glotzen mit dem ersten Argument "--re-interval -f"
genannt wird (nicht um den Leerzeichen aufgeteilt), die es nicht versteht. Gibt es eine Abhilfe für das?
Natürlich können Sie entweder rufen nicht gaffen direkt, sondern in einen Shell-Skript wickeln, die das erste Argument teilt, oder einen Shell-Skript, dass dann ruft gaffen und setzen Sie das Skript in einer anderen Datei, aber ich frage mich, ob es etwas war Art und Weise, dies zu tun in einer Datei.
Das Verhalten von Linien unterscheidet sich von System zu System sheBANG - zumindest in Cygwin tut es nicht teilen Sie die Argumente von Whitespaces. Ich kümmere nur darum, wie es auf einem System zu tun, dass verhält sich wie das; das Skript nicht tragbar sein soll.
Lösung
Das scheint für mich arbeiten mit (g) awk.
#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
# The real awk program starts here
{ print $0 }
Beachten Sie die #!
läuft /bin/sh
, so dass dieses Skript zunächst als ein Shell-Skript interpretiert wird.
Zuerst habe ich einfach versucht "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
, aber awk behandelt, dass als Befehl und bedingungslos jede Eingabezeile ausgedruckt. Deshalb habe ich in der arbitrary_long_name==0
setzen - es soll die ganze Zeit zum Scheitern verurteilt. Man könnte es mit etwas Kauderwelsch Zeichenfolge ersetzen. Im Grunde war ich die Suche nach einem falsch-Zustand in awk, die nicht negativ auf das Shell-Script beeinflussen würden.
In dem Shell-Skript, das arbitrary_long_name==0
definiert eine Variable namens arbitrary_long_name
und setzt es auf =0
entsprechen.
Andere Tipps
Die shebang Linie wird nie als Teil von POSIX angegeben, SUS, LSB oder einer anderen Spezifikation. AFAIK, es ist nicht einmal richtig dokumentiert worden.
Es gibt einen groben Konsens darüber, was es tut: Nehmen Sie alles zwischen den !
und den \n
und exec
es. Die Annahme ist, dass alles, was zwischen dem !
und der \n
ist ein Full absoluter Pfad zum Interpreter. Es gibt keinen Konsens darüber, was passiert, wenn es Leerzeichen enthält.
- Einige Betriebssysteme behandeln einfach die ganze Sache als Pfad. Denn in den meisten Betriebssystemen, Leerzeichen oder Bindestriche in einem Pfad legal sind.
- Einige Betriebssysteme bei Leerzeichen aufgeteilt und behandeln den ersten Teil als Pfad zum Interpreter und der Rest als einzelne Argumente.
- aufgeteilt Einige Betriebssysteme auf der zuerst Leerzeichen und behandeln den vorderen Teil als Weg zum interpeter und den Rest als Single Argument (das ist, was Sie sehen ).
- Einige haben sogar nicht unterstützen shebang Linien an alle .
Zum Glück, 1. und 4. scheinen darauf gestorben, aber 3. ist ziemlich weit verbreitet, so dass Sie einfach nicht darauf vertrauen können mehr als ein Argument zu übergeben.
Und da die Lage der Befehle ist auch in POSIX oder SUS nicht angegeben ist, verwenden Sie in der Regel auf, dass einzelne Argument der ausführbaren vorbei name zu env
, so dass es Dose bestimmen Sie den Speicherort der ausführbaren Datei; z.
#!/usr/bin/env gawk
[Offensichtlich ist dies noch nimmt einen bestimmten Weg für env
, aber es gibt nur sehr wenige Systeme, bei denen es in /bin
lebt, so ist dies im Allgemeinen sicher. Die Lage von env
ist viel mehr standardisiert als die Lage von gawk
oder noch schlimmer so etwas wie python
oder ruby
oder spidermonkey
.]
Was bedeutet, dass Sie nicht wirklich verwenden können alle Argumente an alle .
Ich kam in der gleichen Ausgabe, ohne offensichtliche Lösung wegen der Art, die mit Whitespaces in einem shebang behandelt werden (zumindest unter Linux).
Sie können jedoch mehrere Optionen in einem shebang passieren, solange sie sind Short-Optionen und sie können sein verketteten (die GNU-Weg).
Zum Beispiel können Sie nicht
haben#!/usr/bin/foo -i -f
Sie können sich jedoch
#!/usr/bin/foo -if
Offensichtlich das funktioniert nur, wenn die Optionen kurze Äquivalente haben und keine Argumente haben.
Unter Cygwin und Linux alles nach dem Weg des shebang des Programm als ein Argument analysiert wird.
Es ist möglich, dies in der shebang unter Verwendung eines anderen awk
Skript zu hacken um:
#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
Dies wird {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
in awk auszuführen.
Und dies wird ausführen /usr/bin/gawk --re-interval -f path/to/your/script.awk
in Ihren Systemen Shell.
Obwohl es nicht genau tragbar, beginnend mit coreutils 8,30 und nach seiner Dokumentation Sie in der Lage zu verwenden:
#!/usr/bin/env -S command arg1 arg2 ...
So gegeben:
$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too
Sie erhalten:
% ./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'
und falls Sie sind neugierig showargs
ist:
#!/usr/bin/env sh
echo "\$0 is '$0'"
i=1
for arg in "$@"; do
echo "\$$i is '$arg'"
i=$((i+1))
done
Original Antwort href="https://unix.stackexchange.com/a/477651/4781">.
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''
Der Trick shebang oben Shell ist mehr tragbar als /usr/bin/env
.
In der gaffen Handbuch (http://www.gnu.org/manual/gawk/gawk.html), das Ende des Abschnitts 1.14 beachten Sie, dass Sie nur ein einziges Argument verwenden sollte, wenn gaffen von einer shebang Linie. Er sagt, dass das O alles behandeln, nachdem der Pfad als ein einziges Argument gaffen. Vielleicht gibt es eine andere Möglichkeit, die --re-interval
Option angeben? Vielleicht ist Ihr Skript kann die Shell in der Shebang-Zeile, lief gawk
als Befehl ein, und schließen Sie den Text des Skripts als „hier Dokument“ verweisen.
Warum nicht bash
verwenden und gawk
selbst, vorbei an shebang zu überspringen, las das Drehbuch, und übergeben Sie es als eine Datei in eine zweite Instanz von 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
}
(- das gleiche könnte natürlich auch mit z.B. sed
oder tail
erreicht werden, aber ich denke, es gibt eine Art von Schönheit nur auf bash
abhängig und gawk
selbst;)
Just for fun. Gibt es die folgende ziemlich seltsame Lösung ist, dass Umleitungen stdin und das Programm durch Filedeskriptoren 3 und 4. Sie auch eine temporäre Datei für das Skript erstellen könnten
#!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print "HALLO"}
{print \$1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3
Eine Sache ist ärgerlich darüber. Die Schale auf der Skriptvariable Expansion der Fall ist, so dass Sie jede $ zu zitieren haben (wie in der zweiten Zeile des Skripts fertig) und wahrscheinlich mehr als das
Für eine tragbare Lösung, die Verwendung awk
statt gawk
, rufen Sie den Standard-Bourne-Shell (/bin/sh
) mit Ihrem shebang und invoke awk
direkt auf der Kommandozeile als hier das Programm vorbei dokumentieren, anstatt über stdin:
#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF
Hinweis: kein -f
Argument awk
. Das läßt stdin
für awk
verfügbar Eingabe von zu lesen. Angenommen, Sie gawk
installiert und auf Ihrem PATH
haben, erreicht, dass alles, was ich denke, Sie mit Ihrem ursprünglichen Beispiel vorhatten (vorausgesetzt, Sie den Dateiinhalt wollten der awk-Skript zu sein und nicht der Eingang, die ich Ihr shebang Ansatz denken wäre behandelt es wie).