Comment imprimer son propre nom de script dans mawk?

13

En bash $0contient le nom du script, mais en awk si je crée un script nommé myscript.awk avec le contenu suivant:

#!/usr/bin/awk -f
BEGIN{ print ARGV[0] }

et l'exécuter, il affichera seulement "awk". En outre, ARGV [i] avec i> 0 est utilisé uniquement pour les arguments de script en ligne de commande. Alors, comment faire en sorte qu'il affiche le nom du script, dans ce cas "myscript.awk"?

cipper
la source
J'ai changé le titre de awk en mawk parce que toutes les solutions nécessitent gawk et ne fonctionnent pas avec awk général, et en particulier avec mawk qui est largement utilisé (par exemple par défaut sur Ubuntu)
cipper
Qu'est-ce qui vous fait penser que mawkc'est par défaut sur Ubuntu? Sur ma VM 15.04, la valeur par défaut awkest gawk. Bien que mawk soit installé, ce n'est pas la valeur par défaut.
terdon
1
C'est un script awk si vous l'appelez awk -f myscript.awk. Cependant, cela n'est pas lié au problème en question.
cipper
1
@EdMorton C'est un awkscript car il commence par #!/usr/bin/awk -f. Les scripts shell commencent par #!/bin/sh(ou quelque chose de similaire).
Barmar
1
J'ai parlé à divers experts du shell et j'ai essayé d'obtenir une réponse définitive sur le fait qu'il s'agisse d'un script shell ou awk et, étonnamment, selon POSIX, l'interprétation des fichiers commençant par #! n'est pas défini et n'a pas de nom de type spécifique. Alors que certaines personnes le qualifient de "script d'interpréteur de hachage" plutôt que de script shell ou awk, le consensus semble être qu'il devrait être considéré comme un script awk même si le noyau (pas shell) interprète la première ligne car awk continue doit également pouvoir analyser cette première ligne (sous forme de commentaire) et vous pouvez l'exécuter à l'aide de awk -f file.
Ed Morton du

Réponses:

5

Avec GNU awk 4.1.3 dans bash sur cygwin:

$ cat tst.sh
#!/bin/awk -f
BEGIN { print "Executing:", ENVIRON["_"] }

$ ./tst.sh
Executing: ./tst.sh

Je ne sais pas à quel point c'est portable. Comme toujours, cependant, je n'exécuterais pas un script awk en utilisant un shebang dans un script shell car cela vous prive simplement de fonctionnalités possibles. Restez simple et faites-le à la place:

$ cat tst2.sh
awk -v cmd="$0" '
BEGIN { print "Executing:", cmd }
' "$@"

$ ./tst2.sh
Executing: ./tst2.sh

Ce dernier fonctionnera avec n'importe quel awk moderne dans n'importe quel shell sur n'importe quelle plate-forme.

Ed Morton
la source
Notez que le premier ne fonctionne qu'en bash, zsh ou ksh. Le dernier concerne le script shell, pas le script awk.
cuonglm
2
Je vous remercie! ENVIRON["_"]fonctionne parfaitement, et il n'appelle aucun programme externe. La deuxième option awk -v ...dépend de la façon dont on exécute le script; Je ne veux pas ça.
cipper
1
Appeler votre script tst.shest trompeur. C'est un awkscript, pas un script shell. BEGINn'est pas une commande shell valide.
Barmar
1
D'accord, mais la question de la portabilité n'est pas "est-ce qu'ENVIRON [] est portable" il " ENVIRON["_"]produit le chemin du script du shell appelant lorsqu'il est imprimé depuis chaque awk appelé via un shebang depuis chaque shell"? Je n'appellerais jamais un script awk d'un shebang à personnellement je ne me soucie pas de la réponse mais pensais juste que je le mentionnerais ... Oh je vois dans les commentaires ci-dessus que @cuonglm a répondu qu'il n'est pris en charge que dans certains shells .
Ed Morton
1
Bon point, @Ed. Vérifié comme échouant dans le tiret (qui renvoie la commande précédente (ou bien le shell lui-même) plutôt que la commande actuelle). ksh93 préfixe de manière intéressante le PID dans les astérisques, par exemple *12345*/tmp/test.awk. ARGV[0]est toujours fiable awkdans dash, bash, zsh et ksh93.
Adam Katz
5

Je ne pense pas que cela soit possible selon la gawk documentation :

Enfin, la valeur de ARGV[0](voir la section 7.5 Variables intégrées) varie en fonction de votre système d'exploitation. Certains systèmes awky sont installés, certains mettent le chemin d'accès complet de awk (comme /bin/awk) et certains mettent le nom de votre script («conseil»). Ne vous fiez pas à la valeur de ARGV[0]pour fournir le nom de votre script.

On linuxpeut essayer d'utiliser une sorte de hack sale et comme le soulignent les commentaires de Stéphane Chazelas c'est possible si l'implémentation des awksupports NUL prend en charge:

#!/usr/bin/awk -f

BEGIN { getline t < "/proc/self/cmdline"; split(t, a, "\0"); print a[3]; }
taliezin
la source
votre script tel qu'il semble ne fonctionne pas. Il imprime simplement "k" s'il est appelé avec "awk -f script.awk", et il imprime "s" s'il est appelé par "./script.awk"
cipper
@cipper: Ici, cela fonctionne avec gawket échoue (comme votre description) avec mawk. Intéressant!
Cela fonctionne pour moi sous Linux, awk- 4.0.2. En freebsd avec/proc/curpoc/cmdline , et le awkrésultat est comme le vôtre mais fonctionne avec gawk.
taliezin
Sur Ubuntu par défaut, cela ne fonctionne pas. Ce serait bien de trouver une solution portable.
cipper
1
@taliezin: la réponse de cuonglm n'est pas une solution car elle nécessite de nourrir manuellement le script avec son nom. C'est comme appeler awk -vNAME="myscript.awk" ./myscript.awkpuis imprimer NOM dans le script. Pas une solution.
cipper
5

Je ne connais aucun moyen direct d'obtenir le nom de la commande depuis awk. Vous pouvez cependant le trouver à travers un sous-shell.

rester bouche bée

Avec GNU awk et la pscommande, vous pouvez utiliser l'ID de processus PROCINFO["PID"]pour récupérer le nom de la commande comme solution de contournement. Par exemple:

cmdname.awk

#!/usr/bin/gawk -f

BEGIN {
  ("ps -p " PROCINFO["pid"] " -o comm=") | getline CMDNAME
  print CMDNAME
}

mawk et nawk

Vous pouvez utiliser la même approche, mais dérivez awkle PID de la $PPIDvariable shell spéciale (PID du parent):

cmdname.awk

#!/usr/bin/mawk -f

BEGIN { 
  ("ps -p $PPID -o comm=") | getline CMDNAME
  print CMDNAME
}

Essai

Exécutez le script comme ceci:

./cmdname.awk

Sortie dans les deux cas:

cmdname.awk
Thor
la source
J'ai une erreur: / bin / sh: 1: -o: introuvable
cipper
@cipper: Cela ne fonctionne qu'avec GNU awk, j'ai ajouté la ligne de shebang manquante.
Thor
D'après le manuel de Gawk : Selon POSIX, «expression | getline 'est ambigu si l'expression contient des opérateurs non entre parenthèses autres que' $ '- par exemple,' "echo" "date" | getline 'est ambigu car l'opérateur de concaténation n'est pas entre parenthèses. Vous devez l'écrire comme '("echo" "date") | getline 'si vous voulez que votre programme soit portable sur toutes les implémentations awk.
cipper
1
S'il en a besoin, gawkc'est une gawksolution au lieu d'une awksolution. Je pense que @cipper devrait ajouter son souhait "une solution portable" à la question.
1
@Thor: la réponse de cuonglm n'est pas une solution car elle nécessite de nourrir manuellement le script avec son nom. C'est comme appeler awk -vNAME="myscript.awk" ./myscript.awkpuis imprimer NOM dans le script. Pas une solution.
cipper
4

Avec POSIX awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

Alors:

AWKSCRIPT=test.awk ./test.awk
test.awk
cuonglm
la source
4
Vous y introduisez manuellement le nom du script, ce n'est pas une méthode d'auto-impression
cipper
@cipper: Eh bien, c'est la façon la plus simple et portable que j'imagine.
cuonglm
2
C'est comme appeler awk -vNAME="myscript.awk" ./myscript.awkpuis imprimer la variable NAMEà l'intérieur du script. Pas une solution.
cipper
@cipper: C'est le seul moyen, si vous le mentionnez mawk. Et l'utilisation ENVIRONn'est pas la même chose que l'utilisation -vNAME="myscript.awk", car quand mawkétendra la séquence d'échappement dans NAME.
cuonglm
4

Utiliser GNU awk

Vérification du guide de l'utilisateur de GNU awk - 7.5.2 Variables intégrées qui véhiculent des informations sur lesquelles je suis tombé:

PROCINFO #

Les éléments de ce tableau permettent d'accéder aux informations sur le programme awk en cours d'exécution. Les éléments suivants (classés par ordre alphabétique) sont garantis disponibles:

PROCINFO ["pid"]

ID de processus du processus en cours.

Cela signifie que vous pouvez connaître le PID du programme pendant l'exécution. Ensuite, il s'agit d'utiliser system()pour rechercher le processus avec ce PID donné:

#!/usr/bin/gawk -f
BEGIN{ pid=PROCINFO["pid"]
       system("ps -ef | awk '$2==" pid " {print $NF}'")
}

J'utilise ps -ef, qui affiche le PID sur la 2ème colonne. En supposant que l'exécutiong se fait viaawk -f <script> sans aucun autre paramètre, nous pouvons supposer que le dernier champ de la ligne contient les informations souhaitées.

Dans le cas où nous avions certains paramètres, nous aurions à analyser la ligne différemment - ou, mieux, utiliser certaines des options de ps pour imprimer uniquement les colonnes qui nous intéressent.

Tester

$ awk -f a.awk 
a.awk
$ cp a.awk hello.awk
$ awk -f hello.awk 
hello.awk

Notez également qu'un autre chapitre du guide de l'utilisateur de GNU awk nous dit que ARGV n'est pas la voie à suivre:

1.1.4 Programmes awk exécutables

Enfin, la valeur de ARGV [0] (voir Variables intégrées) varie en fonction de votre système d'exploitation. Certains systèmes y mettent 'awk', certains mettent le chemin complet de awk (comme / bin / awk), et certains mettent le nom de votre script ('conseil'). (dc) Ne vous fiez pas à la valeur de ARGV [0] pour fournir le nom de votre script.

fedorqui
la source
malheureusement PROCINFO n'est qu'une fonctionnalité gawk, pas un awk général. Par exemple, il n'est pas disponible dans mawk (qui est installé par défaut dans ubuntu)
cipper
Je sais ... Pourquoi avez-vous tagué la question avec [gawk] alors?
fedorqui
Tu as raison. Quand j'ai posté la question, je n'étais pas au courant de toutes ces différences entre mawk et gawk. Le tag est maintenant devenu mawk.
cipper
@cipper good:) En fait, je testais avec mawket ne pouvais pas le faire fonctionner, alors j'ai installé gawkdans mon Ubuntu et cela a fonctionné. Une solution peut donc être utilisée gawk: D
fedorqui
1
@terdon, gawkn'est pas installé par défaut sur Ubuntu (ou au moins certaines versions d'Ubuntu, où se mawktrouve l' awkimplémentation par défaut ). IIRC, je devais également l'installer sur Debian.
Stéphane Chazelas