Scrivere script di shell che verranno eseguiti su qualsiasi shell (usando più linee shebang?)


19

Ho appena iniziato ad approfondire gli script di shell, e ho sempre gettato il mio script in un file, contrassegnato chmod +xe quindi fatto /path/to/script.she lasciato che qualunque interprete predefinito sia a suo agio, che presumo fosse zsh perché è quello che Ho usato per il mio guscio. Apparentemente sembra che sia solo /bin/shper impostazione predefinita, anche se eseguo lo script da un prompt di zsh, perché ho iniziato a inserire elementi specifici di zsh nei miei script e non funziona a meno che non esegua zsh /path/to/script.sh.

Per arrivare al punto, ecco le mie domande:

  1. Quale shell esegue gli script quando non c'è nessuna riga shebang ( #!/path/to/shell) all'inizio? Presumo /bin/shma non posso confermare.
  2. Quali sono le "migliori pratiche" in termini di scrittura di script shell che verranno eseguiti su qualsiasi piattaforma? (ok, questo è un po 'aperto)
  3. È possibile scrivere uno script che tenti di usare zsh e torni a bash se zsh non è disponibile? Ho provato a mettere due linee shebang, come di seguito, ma si sbaglia solo bad interpreter: /bin/zsh: no such file or directoryse lo provo su una macchina senza zsh.

    #!/bin/zsh

    #!/bin/bash

Risposte:


26

Quale shell esegue gli script quando non c'è nessuna riga shebang (#! / Path / to / shell) all'inizio? Presumo / bin / sh ma non posso confermare.

Il kernel si rifiuta di eseguire tali script e restituisce ENOEXEC, in modo che il comportamento esatto dipende dal programma che si esegue uno script da .

  • bash 4.2.39 - usa se stesso
  • busybox-ash 1.20.2 - usa se stesso
  • trattino 0.5.7 - corre / bin / sh
  • fish 1.23.1 - si lamenta di ENOEXEC, quindi incolpa il file sbagliato
  • AT&T ksh 93u + 2012.08.01 - usa se stesso
  • mksh R40f - corre / bin / sh
  • pdksh 5.2.14 - run / bin / sh
  • sh-heirloom 050706 - usa se stesso
  • tcsh 6.18.01 - run / bin / sh
  • zsh 5.0.0 - corre / bin / sh
  • cmd.exe 5.1.2600 - ti guarda divertente.

In glibc , funzioni execv()o execve()semplicemente restituisce ENOEXEC. Ma execvp()nasconde questo codice di errore e invoca automaticamente / bin / sh. (Questo è documentato in exec (3p) .)

Quali sono le "migliori pratiche" in termini di scrittura di script shell che verranno eseguiti su qualsiasi piattaforma? (ok, questo è un po 'aperto)

Attenersi she solo alle funzionalità definite da POSIX o andare semplicemente alla bash (che è ampiamente disponibile) e menzionarlo nelle vostre esigenze se distribuirlo.

(Ora che ci penso, Perl - o forse Python - sarebbe ancora più portatile, per non parlare della migliore sintassi.)

Aggiungi sempre la linea shebang. Se usi bash o zsh, usa #!/usr/bin/env bashinvece di hardcoding il percorso della shell. (Tuttavia, la shell POSIX è garantita /bin/sh, quindi saltare envin quel caso.)

(Sfortunatamente, anche /bin/shnon è sempre lo stesso. Il programma GNU autoconf deve affrontare molte stranezze diverse .)

È possibile scrivere uno script che tenti di usare zsh e torni a bash se zsh non è disponibile? Ho provato a mettere due righe di shebang, come di seguito, ma solo errori con un interprete errato: / bin / zsh: nessun file o directory simile se lo provo su una macchina senza zsh.

Ci può essere solo una linea shebang; tutto ciò che segue il carattere newline non viene nemmeno letto dal kernel e trattato come un commento da shell.

È possibile scrivere uno script che viene eseguito come #!/bin/sh, controlla quale shell è disponibile e viene eseguita exec zsh "$0" "$@"o in exec bash "$0" "$@"base al risultato. Tuttavia, la sintassi utilizzata da bash e zsh è così diversa in vari punti che non consiglierei di farlo per la tua sanità mentale.


1
come hai fatto a rintracciare ciò che ogni shell stava effettivamente chiamando quando ha ricevuto ENOEXEC?
swrobel

2
@SWrobel: utilizzando strace -f -e fork,clone,execve. Alcune shell hanno continuato a funzionare /bin/shdopo esito negativo; altri hanno interpretato la sceneggiatura da soli.
Grawity

1
@SWrobel: un altro metodo consiste nell'eseguire uno script composto da readlink /proc/$$/exe.
Grawity

2
Vedi anche la risposta di Stéphane Chazelas a Quale interprete shell esegue uno script senza shebang? (duplicato su più siti della sottointerrogazione n. 1)
G-Man dice 'Reinstate Monica' il

1
Per cshe tcsh, il comportamento dipende dal fatto che lo script inizi con #(nel qual caso si invocano invece di sh per interpretare lo script). Questo risale al tempo in cui csh supportava i commenti ma non la shell Bourne, quindi #un suggerimento era che era uno script csh.
sch

2

1) La shell corrente in cui stai eseguendo. (Qualunque shell possa essere)

2) Stick con lo stesso tipo di shell (bash / dash / ash / csh / qualunque sia il tuo sapore) e assicurati che le tue "piattaforme supportate" installino la shell che desideri utilizzare per impostazione predefinita. Inoltre, prova a utilizzare i comandi comunemente disponibili sui sistemi. Evita le opzioni specifiche della macchina.

3) In realtà non esiste una logica "if-then-else" interpreter directive. Dovresti specificare una shell che dovrebbe esistere su tutti i sistemi che desideri supportare ... ovvero #!/bin/bashspecificare un generico #!/bin/shpurché lo script sia abbastanza generico su tutte le shell.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.