130 votes

Comment utiliser plusieurs arguments avec un shebang (c'est-à-dire #!)?

J'aimerais exécuter une gawk script avec --re-interval à l'aide d'une arborescence. La "naïve" de l'approche de

#!/usr/bin/gawk --re-interval -f
... awk script goes here

ne fonctionne pas, puisque gawk est appelée avec le premier argument "--re-interval -f" (pas répartis autour de l'espace), 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 à s'émerveiller et de mettre le script dans un autre fichier, mais je me demandais si il y avait moyen de faire cela dans un seul fichier.

Le comportement de shebang lignes diffère d'un système à l'autre - au moins dans Cygwin, il ne se fend pas les arguments par des espaces. Je viens de soins sur la façon de le faire sur un système qui se comporte comme ça; le script n'est pas destiné à être portables.

163voto

Jörg W Mittag Points 153275

La ligne shebang n'a jamais été spécifiée dans POSIX, SUS, LSB ou toute autre spécification. Autant que je sache, il n'a même pas été correctement documentée.

Il s'agit d'un rough consensus sur ce qu'il fait: prendre tout ce qui est entre l' ! et de la \n et exec . L'hypothèse est que tout ce qui est entre l' ! et de la \n est une intégrale de chemin d'accès absolu à l'interprète. Il n'y a pas de consensus sur ce qui se passe s'il contient des espaces.

  1. Certains systèmes d'exploitation simplement traiter l'ensemble de la chose que le chemin d'accès. Après tout, dans la plupart des systèmes d'exploitation, des espaces ou des tirets sont légales dans un chemin.
  2. Certains systèmes d'exploitation divisé en espaces et traiter la première partie que le chemin de l'interprète et le reste des arguments personnels.
  3. Certains systèmes d'exploitation divisé à la première espaces et traiter la partie avant que le chemin d'accès à l'interprète et le reste comme un seul argument (qui est ce que vous voyez).
  4. Certains même ne prennent pas en charge shebang lignes à tous.

Heureusement, 1. et 4. semblent avoir disparu, mais 3. est assez répandue, de sorte que vous ne peut tout simplement pas compter sur d'être en mesure de passer plus d'un argument.

Et puisque le lieu de commandes est pas spécifiée dans POSIX ou SUS, vous utilisez généralement que seul argument en passant le fichier exécutable du nom d' env afin qu' il puisse déterminer l'emplacement de l'exécutable; par exemple:

#!/usr/bin/env gawk

[Évidemment, ce toujours suppose un chemin particulier pour env, mais il n'existe que très peu de systèmes où il vit en /bin, donc c'est généralement sans danger. L'emplacement de env est beaucoup plus standardisée que l'emplacement de gawk , ou pire encore, quelque chose comme python ou ruby ou spidermonkey.]

Ce qui signifie que vous ne pouvez utiliser aucun des arguments à tous.

27voto

Aaron McDaid Points 7761

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 }

Remarque l' #! s'exécute /bin/sh, de sorte que ce script est d'abord interprétée comme un script shell.

Au début, j'ai simplement tenté "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@", mais awk traitée comme une commande et imprimés chaque ligne de saisie sans condition. C'est pourquoi je l'ai mis dans l' arbitrary_long_name==0 - c'est censé faire échouer tout le temps. Vous pourriez le remplacer par n'importe quoi de la chaîne. En fait, je cherchais un faux-condition dans awk qui ne les empêcherait pas de script shell.

Dans le script shell, l' arbitrary_long_name==0 définit une variable nommée arbitrary_long_name et fixe égal à =0.

13voto

ℝaphink Points 1438

Je suis tombé sur le même problème, sans solution apparente en raison de la façon dont les espaces sont traités dans un shebang (au moins sous Linux).

Toutefois, vous pouvez passer plusieurs options dans un shebang, tant qu'ils sont à court d'options et ils peuvent être concaténées (GNU façon).

Par exemple, vous ne pouvez pas avoir

#!/usr/bin/foo -i -f

mais vous pouvez avoir

#!/usr/bin/foo -if

Evidemment, cela ne fonctionne que lorsque les options ont court équivalents et ne pas prendre des arguments.

3voto

bta Points 22525

Dans le gawk manuel (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 rester bouche bée à partir d'une ligne shebang. Il est dit que l'OS va traiter tout ce qui est après le chemin d'accès à gawk comme un seul argument. Peut-être il ya une autre façon de spécifier l' --re-interval option? Peut-être que votre script peut faire référence à votre shell dans la ligne shebang, exécutez gawk comme une commande, et d'inclure le texte de votre script comme "here document".

0voto

hstoerr Points 5771

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 effectue un développement variable du script, vous devez donc citer chaque $ (comme dans la deuxième ligne du script) et probablement plus que cela.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X