Comment utiliser plusieurs arguments pour awk avec un shebang (i.e. #!)?
j'aimerais exécuter un script gawk 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, puisque gawk est appelé avec le premier argument "--re-interval -f"
(non divisé autour de l'espace blanc), qu'il ne comprend pas. Est-il une solution pour cela?
bien sûr, vous pouvez soit pas appel gawk directement, mais l'envelopper dans un script shell qui divise le premier argument, ou faire un script shell qui appelle ensuite gawk et mettre le script dans un autre fichier, mais je me demandais s'il y avait un moyen de le faire dans un fichier.
le comportement des lignes de shebang diffère d'un système à l'autre - au moins dans Cygwin il ne divise pas les arguments par des espaces blancs. Je me soucie juste de savoir comment le faire sur un système qui se comporte comme cela; le script n'est pas censé être portable.
9 réponses
Cela semble fonctionner pour moi avec (g)awk.
#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" ""151900920"" "$@"
# The real awk program starts here
{ print "151900920" }
notez que #!
exécute /bin/sh
, donc 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" ""151930920"" "$@"
, mais awk a traité cela comme une commande et a imprimé chaque ligne d'entrée inconditionnellement. C'est pourquoi j'ai mis le arbitrary_long_name==0
- il est censé échouer tout le temps. Vous pourriez le remplacer par du charabia. En gros, j'étais à la recherche pour une fausse condition dans awk qui n'affecterait pas négativement 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 comme =0
.
la ligne de shebang n'a jamais été spécifiée dans POSIX, SUS, LSB ou toute autre spécification. AFAIK, il n'a même pas été correctement documenté.
il y a un consensus grossier sur ce qu'il fait: prenez tout entre le !
et le \n
et exec
il. L'hypothèse est que tout entre le !
et le \n
est un chemin absolu vers l'interprète. Il n'y a pas de consensus sur ce qui se passe si contient des espaces.
- certains systèmes d'exploitation traitent simplement la chose entière comme le chemin. Après tout, dans la plupart des systèmes d'exploitation, les espaces ou les tirets sont légaux dans un chemin.
- certains systèmes d'exploitation se séparent à whitespace et traitent la première partie comme le chemin vers l'interpréteur et le reste comme des arguments individuels.
- certains systèmes d'exploitation scindé à la premier espaces et de traiter les la partie avant comme le chemin vers l'interpètre et le reste comme un simple argument (qui est ce que vous voyez).
- certains ne supportent même pas les lignes de shebang du tout .
Heureusement, 1. et 4. semblent avoir disparu, mais 3. est assez répandue, de sorte que vous ne pouvez tout simplement pas compter sur la possibilité de passer plus d'un argument.
et comme l'emplacement des commandes est également non spécifié dans POSIX ou SUS, vous utilisez généralement ce seul argument en passant le "nom" de l'exécutable à env
de sorte que it puisse déterminer l'emplacement de l'exécutable; par exemple:
#!/usr/bin/env gawk
[évidemment, ce encore assume un chemin particulier pour env
, mais il n'y a que très peu de systèmes où il vit dans /bin
, ce qui est 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 réellement utiliser tout arguments du tout .
je suis tombé sur la même question, sans solution apparente en raison de la façon dont les espaces blancs sont traités dans un shebang (au moins sur Linux).
cependant, vous pouvez passer plusieurs options dans un shebang, à condition qu'elles soient courtes options 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 pas d'arguments.
sous Cygwin et Linux tout ce qui suit le chemin du shebang est analysé au programme comme un seul argument.
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 shell système.
#!/bin/sh
''':'
exec YourProg -some_options ""151900920"" "$@"
'''
le shebang de coquille ci-dessus est plus portable que /usr/bin/env
.
In the gawk manual (http://www.gnu.org/manual/gawk/gawk.html), la fin de la section 1.14 notez que vous ne devez utiliser qu'un seul argument lors de l'exécution de gawk à partir d'une ligne shebang. Il est dit que L'OS traitera tout après le chemin de gawk comme un argument unique. Peut-être y a-t-il une autre façon de spécifier l'option --re-interval
? Peut-être que votre script peut faire référence à votre shell dans la ligne de shebang, lancer gawk
comme une commande, et inclure le texte de votre script comme un " ici document."
pourquoi ne pas utiliser bash
et gawk
lui-même, pour passer devant shebang, lire le script, et le passer comme un fichier à une deuxième instance de gawk [--with-whatever-number-of-params-you-need]
?
#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' "151900920" )
exit
{
print "Program body goes here"
print
}
(- la même chose pourrait naturellement aussi être accomplie avec par exemple sed
ou tail
, mais je pense qu'il y a une sorte de beauté qui dépend seulement de bash
et gawk
lui-même;)
juste pour le plaisir: il y a la solution suivante assez étrange 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 ennuyeuse à ce sujet: le shell fait l'expansion variable sur le script, donc vous devez citer chaque $ (Comme fait dans la deuxième ligne du script) et probablement plus que cela.
pour une solution portable, utilisez awk
plutôt que gawk
, invoquez le shell BOURNE standard ( /bin/sh
) avec votre shebang, et invoquez awk
directement, en passant le programme sur la ligne de commande comme un document ici plutôt que via stdin:
#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF
Note: no -f
argument à awk
. Cela laisse stdin
disponible pour awk
à lire en entrée. En supposant que vous avez gawk
installé et sur votre PATH
, cela réalise tout ce que je pense que vous essayiez de faire avec votre exemple original (en supposant que vous vouliez que le contenu du fichier soit le script awk et non l'entrée, ce que je pense que votre approche shebang l'aurait traité comme).