Vous ne pouvez pas, de manière portative, mettre plus d'un argument sur une #!
ligne . Cela signifie seulement un chemin complet et un argument (par exemple #!/bin/sed -f
ou #!/usr/bin/sed -f
), ou #!/usr/bin/env
et aucun argument à l'interpréteur.
Une solution de contournement pour obtenir un script portable consiste à utiliser #!/bin/sh
un wrapper shell, en passant le script sed comme argument de ligne de commande. Notez que ceci n'est pas autorisé par POSIX (les scripts multi-instructions doivent être écrits avec un -e
argument séparé pour chaque instruction pour la portabilité), mais cela fonctionne avec de nombreuses implémentations.
#!/bin/sh
exec sed '
s/a/b/
' "$@"
Pour un long script, il peut être plus pratique d'utiliser un hérédoc. Un avantage d'un hérédoc est que vous n'avez pas besoin de citer les guillemets simples à l'intérieur, le cas échéant. Un inconvénient majeur est que le script est alimenté par sed sur son entrée standard, avec deux conséquences ennuyeuses. Certaines versions de sed nécessitent -f /dev/stdin
au lieu de -f -
, ce qui pose un problème de portabilité. Pire, le script ne peut pas agir comme un filtre, car l'entrée standard est le script et ne peut pas être les données.
#!/bin/sh
exec sed -f - -- "$@" <<'EOF'
s/a/b/
EOF
L'inconvénient de l'hérédoc peut être corrigé par une utilisation utile de cat
. Dans la mesure où cela place à nouveau l'intégralité du script sur la ligne de commande, il n'est pas compatible POSIX, mais largement portable en pratique.
#!/bin/sh
exec sed "$(cat <<'EOF')" -- "$@"
s/a/b/
EOF
Une autre solution consiste à écrire un script qui peut être analysé à la fois par sh et par sed. C'est portable, assez efficace, juste un peu moche.
#! /bin/sh
b ()
{
x
}
i\
f true; then exec sed -f "$0" "$@"; fi
: ()
# sed script starts here
s/a/b/
Explications:
- Sous sh: définir une fonction appelée
b
; le contenu n'a pas d'importance tant que la fonction est syntaxiquement bien formée (en particulier, vous ne pouvez pas avoir de fonction vide). Ensuite, si vrai (c'est-à-dire toujours), exécutez sed
le script.
- Sous sed: branchez-vous sur l'
()
étiquette, puis une entrée bien formée. Ensuite, une i
commande, qui n'a aucun effet car elle est toujours ignorée. Enfin l' ()
étiquette suivie de la partie utile du script.
- Testé sous GNU sed, BusyBox et OpenBSD. (Vous pouvez vous en sortir avec quelque chose de plus simple sur GNU sed, mais OpenBSD sed est pointilleux sur les parties qu'il ignore.)