Errore shebang di FreeBSD
Vorrei mettere shebang #!/bin/sh -eufo pipefail
nella mia sceneggiatura. Ma ci sono diverse cose strane:
- Lo script fallirebbe con quella frase in FreeBSD ma non se eseguito su MacOS
- su FreeBSd, lo stesso shebang funziona quando eseguito direttamente dalla riga di comando (anche
/bin/sh
).
>>> sh -eufo pipefail -c 'echo hi' # this works
hi
>>> cat <<EOF > script
#!/bin/sh -eufo pipefail
echo hi
EOF
>>> chmod +x ./script
>>> ./script # this doesn't work on FreeBSD but works on MacOS
Illegal option -o ./script
>>> cat ./script
#!/bin/sh -eufo pipefail
echo hi
>>> uname -a
FreeBS 11.3-RELEASE-p7
Risposte
MacOS mantiene ancora il vecchio comportamento di FreeBSD di prima del 2005. Nel 2005, c'è stato un cambiamento importante nel modo in cui il kernel di FreeBSD gestiva #!
all'inizio di un file eseguibile passato a execve()
, per renderlo più in linea con alcuni altri kernel del sistema operativo, inclusi Linux e il kernel NetBSD.
Il commento nel codice sorgente del kernel NetBSD cerca di dipingere questo come un universale:
* raccogliere l'argomento della shell. tutto dopo il nome della shell * viene passato come UN argomento; questo è il corretto (storico) * comportamento.-kern/exec-script.c
. NetBSD. righe 189 e segg ..
In realtà non lo è. Sven Mascheck ha eseguito alcuni test circa un decennio fa e ci sono quattro comportamenti di base, quello AT&T Unix System 5 ha la stessa pretesa di essere un comportamento "storico corretto" quanto quello 4.2BSD:
- Ignora i caratteri (prima di 4.2BSD e AT&T Unix System 5).
- Passa l'intera stringa in un unico argomento (4.2BSD, NetBSD, Linux e FreeBSD dal 2005 in poi).
- Dividi la stringa di spazi bianchi e passala come più argomenti (FreeBSD prima del 2005 e MacOS).
- Dividi la stringa in spazi bianchi e passa solo il primo argomento (AT&T Unix System 5 e Solaris)
Ho incluso solo i sistemi operativi rilevanti per questa risposta tra parentesi. M. Mascheck ha controllato molto di più, come ha fatto Ahmon Dancy nella discussione di FreeBSD Problem Report 16393. Vedere la lettura successiva per gli elenchi completi.
Ciò che ha portato le cose alla testa in FreeBSD nel 2005 è stato che, ironicamente, FreeBSD non era così semplice. Era stata introdotta una modifica che aveva lo scopo di far funzionare effettivamente le cose scritte in libri popolari su Perl: gli argomenti venivano saltati dopo un carattere di commento. I libri avevano consigliato cose come:
#! / bin / sh - # - * - perl - * -- Larry Wall, Tom Christiansen, Jon Orwant (2000). Programming Perl: 3a edizione . O'Reilly Media. ISBN 9780596000271. p. 488.
PR 16393 nel 2000 era un modo per far sì che il kernel gestisse script Perl eseguibili, scritti nel modo in cui Larry Wall aveva detto che avrebbero funzionato. Tuttavia, ha rotto altre cose e non ha funzionato completamente.
C'erano alcuni avanti e indietro su questo. Infine, nel 2005 il meccanismo per far funzionare l'idea di Larry Wall et al. È stato spostato dal kernel, che è stato fatto per funzionare in modo compatibile con Linux, NetBSD e 4.2BSD (piuttosto che Solaris e AT&T Unix System 5) e realizzato la responsabilità di sh
.
Il comportamento dal 2005 è stato quindi che la shell ottiene tre argomenti, il secondo argomento è l'intera coda della #!
riga, e invocare lo script direttamente con execve()
è effettivamente lo stesso che invocare:
sh '-eufo pipefail' ./script
Dovrebbe essere abbastanza ovvio il motivo per cui la shell Almquist (che è ciò che sh
è su FreeBSD) pensa che ./script
sia l'argomento opzione per l' -o
opzione, e che tratta la pipefail
parte come ulteriori opzioni di una sola lettera raccolte dietro -
(che non ha intorno all'elaborazione ancora).
Un'alternativa ovvia è anche quella di avere set -o pipefail
come primo comando nello script, come sottolineato inhttps://unix.stackexchange.com/a/533418/5132per la shell Bourne Again . Questo è stato aggiunto solo alla shell di FreeBSD Almquist nel 2019, tuttavia, e quindi è disponibile solo nelle versioni molto recenti di FreeBSD. (La shell Debian Almquist non l'ha ancora aggiunta, a partire dal 2020.)
Ulteriore lettura
- Puntatori ad alcuni dei precedenti: https://unix.stackexchange.com/a/489688/5132
- Sven Mascheck. " Risultati dei test da vari sistemi ". La
#!
magia, i dettagli sul meccanismo shebang / hash-bang su varie versioni di Unix . www.in-ulm.de/~mascheck . - Garance A Drosihn (2005-02-23). Bug in #! elaborazione - ancora una volta . mailing list di freebsd-arch.
- ryand (2000-01-27).
/bin/sh
non elimina i commenti sulla linea di Shebang . Rapporto sui problemi di FreeBSD 16393. - Garance A Drosihn (2005). Nota di aggiornamento per il 28 maggio 2005: modifica nella gestione delle opzioni di script di shell . people.freebsd.org/~gad.
sh
. Manuale dei comandi generali BSD . 24/02/2019. freebsd.org.- Wolfram Schneider (12/12/2017). Ottieni lo stato di uscita del processo reindirizzato a un altro:
set -o pipefail
manca per/bin/sh
. Rapporto sui problemi di FreeBSD 224270. - Ibrahim Ghazal (2020-06-30). Stato di
set -o pipefail
. Mailing list della shell Debian Almquist.
Anche se il tuo #!
utilizzo non è portabile perché utilizza più del semplice:
#!/bin/sh
o il singolo argomento comunemente supportato come in:
#!/bin/sh -oneflag
Il vero problema è che stai usando un'opzione non portatile -o pipefail
.
Questa è un'opzione di ksh93
e bash
non è supportata da altre shell.
Sfondo:
Su MacOS,
/bin/sh
èbash
che è stato compilato in un modo specifico (ad esempio per far funzionare le sequenze di escapeecho
di default) per renderlo conforme a POSIX. Poiché bash supportapipefail
(vedi sopra), funziona su MacOS.Su FreeBSD,
/bin/sh
èash
che non supportapipefail
.
Hai due possibili modi per andare:
Non usare
set -o pipefail
Aspetta due anni e riprova. Molto probabilmente funzionerà, perché 10 mesi fa abbiamo deciso di aggiungere questa opzione al prossimo standard POSIX (numero 8), vederehttps://www.austingroupbugs.net/view.php?id=789e poiché il prossimo standard POSIX sarà pubblicato in ca. un anno, v'è una grande opportunità che FreeBSD aggiungerà il supporto per
set -o pipefail
alash
più presto.