Sous Linux, le shebang n'est pas très flexible; selon plusieurs réponses (réponse de Stephen Kitt et Jörg W Mittag ), il n'y a pas de moyen désigné pour passer plusieurs arguments dans une ligne de shebang.
Je ne sais pas si cela sera utile à personne, mais j'ai écrit un court script pour implémenter la fonctionnalité manquante. Voir https://gist.github.com/loxaxs/7cbe84aed1c38cf18f70d8427bed1efa .
Il est également possible d'écrire des solutions de contournement intégrées. Ci-dessous, je présente quatre solutions de contournement indépendantes de la langue appliquées au même script de test et le résultat de chaque impression. Je suppose que le script est exécutable et est dedans /tmp/shebang
.
Envelopper votre script dans un hérédoc bash à l'intérieur de la substitution de processus
Pour autant que je sache, c'est la façon la plus fiable de le faire indépendamment du langage. Il permet de passer des arguments et préserve stdin. L'inconvénient est que l'interpréteur ne connaît pas l'emplacement (réel) du fichier qu'il lit.
#!/bin/bash
exec python3 -O <(cat << 'EOWRAPPER'
print("PYTHON_SCRIPT_BEGINNING")
from sys import argv
try:
print("input() 0 ::", input())
print("input() 1 ::", input())
except EOFError:
print("input() caused EOFError")
print("argv[0] ::", argv[0])
print("argv[1:] ::", argv[1:])
print("__debug__ ::", __debug__)
# The -O option changes __debug__ to False
print("PYTHON_SCRIPT_END")
EOWRAPPER
) "$@"
echo -e 'aa\nbb' | /tmp/shebang 'arg1' 'arg2 contains spaces' 'arg3\ uses\ \\escapes\\'
Impressions d' appel :
PYTHON_SCRIPT_BEGINNING
input() 0 :: aa
input() 1 :: bb
argv[0] :: /dev/fd/62
argv[1:] :: ['arg1', 'arg2 contains spaces', 'arg3\\ uses\\ \\\\escapes\\\\']
__debug__ :: False
PYTHON_SCRIPT_END
Notez que la substitution de processus produit un fichier spécial. Cela peut ne pas convenir à tous les exécutables. Par exemple, se #!/usr/bin/less
plaint:/dev/fd/63 is not a regular file (use -f to see it)
Je ne sais pas s'il est possible d'avoir heredoc inside substitution de processus dans le tiret.
Envelopper votre script dans un hérédoc simple
Plus court et plus simple, mais vous ne pourrez pas accéder à stdin
partir de votre script et cela nécessite que l'interpréteur puisse lire et exécuter un script à partir de stdin
.
#!/bin/sh
exec python3 - "$@" << 'EOWRAPPER'
print("PYTHON_SCRIPT_BEGINNING")
from sys import argv
try:
print("input() 0 ::", input())
print("input() 1 ::", input())
except EOFError:
print("input() caused EOFError")
print("argv[0] ::", argv[0])
print("argv[1:] ::", argv[1:])
print("__debug__ ::", __debug__)
# The -O option changes __debug__ to False
print("PYTHON_SCRIPT_END")
EOWRAPPER
echo -e 'aa\nbb' | /tmp/shebang 'arg1' 'arg2 contains spaces' 'arg3\ uses\ \\escapes\\'
Impressions d' appel :
PYTHON_SCRIPT_BEGINNING
input() caused EOFError
argv[0] :: -
argv[1:] :: ['arg1', 'arg2 contains spaces', 'arg3\\ uses\\ \\\\escapes\\\\']
__debug__ :: True
PYTHON_SCRIPT_END
Utiliser un system()
appel awk mais sans arguments
Transmet correctement le nom du fichier exécuté, mais votre script ne recevra pas les arguments que vous lui donnez. Notez que awk est la seule langue que je connaisse dont l'interprète est installé sur linux par défaut et lit ses instructions depuis la ligne de commande par défaut.
#!/usr/bin/gawk BEGIN {system("python3 -O " ARGV[1])}
print("PYTHON_SCRIPT_BEGINNING")
from sys import argv
print("input() 0 ::", input())
print("input() 1 ::", input())
print("argv[0] ::", argv[0])
print("argv[1:] ::", argv[1:])
print("__debug__ ::", __debug__)
# The -O option changes __debug__ to False
print("PYTHON_SCRIPT_END")
echo -e 'aa\nbb' | /tmp/shebang 'arg1' 'arg2 contains spaces' 'arg3\ uses\ \\escapes\\'
Impressions d' appel :
PYTHON_SCRIPT_BEGINNING
input() 0 :: aa
input() 1 :: bb
argv[0] :: /tmp/shebang
argv[1:] :: []
__debug__ :: False
PYTHON_SCRIPT_END
Utilisez l' system()
appel awk 4.1+ , à condition que vos arguments ne contiennent pas d'espaces
Bien, mais seulement si vous êtes sûr que votre script ne sera pas appelé avec des arguments contenant des espaces. Comme vous pouvez le voir, vos arguments contenant des espaces seraient divisés, à moins que les espaces ne soient échappés.
#!/usr/bin/gawk @include "join"; BEGIN {system("python3 -O " join(ARGV, 1, ARGC, " "))}
print("PYTHON_SCRIPT_BEGINNING")
from sys import argv
print("input() 0 ::", input())
print("input() 1 ::", input())
print("argv[0] ::", argv[0])
print("argv[1:] ::", argv[1:])
print("__debug__ ::", __debug__)
# The -O option changes __debug__ to False
print("PYTHON_SCRIPT_END")
echo -e 'aa\nbb' | /tmp/shebang 'arg1' 'arg2 contains spaces' 'arg3\ uses\ \\escapes\\'
Impressions d' appel :
PYTHON_SCRIPT_BEGINNING
input() 0 :: aa
input() 1 :: bb
argv[0] :: /tmp/shebang
argv[1:] :: ['arg1', 'arg2', 'contains', 'spaces', 'arg3 uses \\escapes\\']
__debug__ :: False
PYTHON_SCRIPT_END
Pour les versions awk inférieures à 4.1, vous devrez utiliser la concaténation de chaînes à l'intérieur d'une boucle for, voir l'exemple de fonction https://www.gnu.org/software/gawk/manual/html_node/Join-Function.html .