Je voudrais exécuter un gawk script avec --re-interval
en utilisant un Shebang. L'approche "naïve" de
#!/usr/bin/gawk --re-interval -f
... awk script goes here
ne fonctionne pas car gawk est appelé avec le premier argument "--re-interval -f"
(non divisé autour de l'espace), qu'il ne comprend pas. Y at-il une solution de contournement pour cela?
Bien sûr, vous pouvez non seulement appeler directement gawk mais l'envelopper dans un script shell qui divise le premier argument, ou créer un script shell qui appelle ensuite gawk et le placer dans un autre fichier, mais je me demandais s'il y avait un moyen de le faire. ceci dans un fichier.
Le comportement des lignes Shebang diffère d’un système à l’autre - du moins dans Cygwin , il ne scinde pas les arguments par des espaces. Je me soucie juste de la façon de le faire sur un système qui se comporte comme ça; le script n'est pas conçu pour être portable.
Cela semble fonctionner pour moi avec (g) awk.
#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
# The real awk program starts here
{ print $0 }
Notez que #!
exécute /bin/sh
, de sorte que ce script est d'abord interprété comme un script Shell.
Au début, j’ai simplement essayé "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"
, mais awk a traité cela comme une commande et a imprimé chaque ligne d’entrée sans condition. C'est pourquoi j'ai mis le arbitrary_long_name==0
- il est supposé échouer tout le temps. Vous pouvez le remplacer par une chaîne de charabia. En gros, je recherchais une fausse condition dans awk qui n’affecterait pas le script Shell.
Dans le script Shell, le arbitrary_long_name==0
définit une variable appelée arbitrary_long_name
et la définit égale à =0
.
La ligne Shebang n'a jamais été spécifiée dans le cadre de POSIX, SUS, LSB ou de toute autre spécification. Autant que je sache, il n'a même pas été correctement documenté.
Il y a un consensus approximatif sur ce qu'il fait: prend tout entre le !
et le \n
et le exec
le. L'hypothèse est que tout ce qui se situe entre !
et \n
est un chemin absolu complet vers l'interpréteur. Il n'y a pas de consensus sur ce qui se passe s'il contient des espaces.
Heureusement, 1. et 4. semblent avoir disparu, mais 3. est assez répandu, vous ne pouvez donc pas simplement compter sur la capacité de passer plus d'un argument.
De plus, l'emplacement des commandes n'étant pas spécifié dans POSIX ni dans SUS, vous utilisez généralement cet argument unique en transmettant le name de l'exécutable à env
afin que it puisse déterminer l'emplacement de l'exécutable; par exemple.:
#!/usr/bin/env gawk
[Évidemment, ceci still suppose un chemin particulier pour env
, mais il n’ya que très peu de systèmes dans lesquels il se trouve dans /bin
, ce qui est donc généralement sûr. L'emplacement de env
est beaucoup plus standardisé que l'emplacement de gawk
ou même pire, quelque chose comme python
ou Ruby
ou spidermonkey
.]
Ce qui signifie que vous ne pouvez pas utiliser aucun arguments du tout.
Je suis tombé sur le même problème, sans solution apparente à cause de la façon dont les espaces blancs sont traités dans un Shebang (au moins sous Linux).
Cependant, vous pouvez passer plusieurs options dans un Shebang, à condition qu'elles soient options courtes et qu'elles puissent être concaténées (la manière GNU).
Par exemple, vous ne pouvez pas avoir
#!/usr/bin/foo -i -f
mais vous pouvez avoir
#!/usr/bin/foo -if
Évidemment, cela ne fonctionne que lorsque les options ont des équivalents courts et ne prennent aucun argument.
Sous Cygwin et Linux, tout ce qui suit le chemin du Shebang est analysé comme un argument au programme.
Il est possible de contourner cela en utilisant un autre script awk
à l'intérieur du Shebang:
#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
Ceci exécutera {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}
dans awk.
Et ceci exécutera /usr/bin/gawk --re-interval -f path/to/your/script.awk
dans votre système Shell.
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''
Le tour ci-dessus de Shell Shebang est plus portable que /usr/bin/env
.
Dans le manuel de gawk (http://www.gnu.org/manual/gawk/gawk.html), à la fin de la section 1.14, vous devez utiliser un seul argument lorsque vous exécutez gawk à partir d'une ligne Shebang. Il dit que le système d'exploitation traitera tout ce qui suit le chemin de gawk comme un argument simple. Peut-être existe-t-il un autre moyen de spécifier l'option --re-interval
? Peut-être que votre script peut faire référence à votre shell dans la ligne Shebang, exécuter gawk
en tant que commande et inclure le texte de votre script en tant que "document ici".
Pourquoi ne pas utiliser bash
et gawk
lui-même, pour ignorer Shebang, lire le script et le transmettre en tant que fichier à une seconde instance de 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
}
(-la même chose pourrait naturellement aussi être accomplie avec, par exemple, sed
ou tail
, mais je pense qu’il ya une sorte de beauté qui dépend uniquement de bash
et gawk
elle-même;)
Bien que n'étant pas exactement portable, à partir de coreutils 8.30 et selon sa documentation vous pourrez utiliser:
#!/usr/bin/env -S command arg1 arg2 ...
Donc, étant donné:
$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too
tu auras:
% ./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'
et si vous êtes curieux, showargs
est:
#!/usr/bin/env sh
echo "\$0 is '$0'"
i=1
for arg in "$@"; do
echo "\$$i is '$arg'"
i=$((i+1))
done
Réponse originale ici .
Juste pour le plaisir: il existe la solution assez étrange suivante qui redirige stdin et le programme à travers les descripteurs de fichier 3 et 4. Vous pouvez également créer un fichier temporaire pour le 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
Une chose est agaçante à ce sujet: le shell développe des variables variables sur le script. Vous devez donc indiquer chaque $ (comme dans la deuxième ligne du script) et probablement plus que cela.