Pisanie skryptów powłoki, które będą działać na dowolnej powłoce (używając wielu linii shebang?)

19

Właśnie zacząłem zagłębiać się w skrypty powłoki i zawsze po prostu wrzucałem swój skrypt do pliku, zaznaczałem go, chmod +xa następnie robiłem /path/to/script.shi pozwalałem, aby dowolny interpreter był domyślny, co założyłem, że to zsh, ponieważ to właśnie Użyłem mojej muszli. Najwyraźniej wydaje się, że jest to /bin/shdomyślnie, nawet jeśli wykonuję skrypt z wiersza polecenia zsh, ponieważ zacząłem umieszczać w skryptach rzeczy specyficzne dla zsh i nie działa, chyba że uruchomię zsh /path/to/script.sh.

Aby przejść do sedna, oto moje pytania:

  1. Która powłoka wykonuje skrypty, gdy na początku nie ma linii shebang ( #!/path/to/shell)? Zakładam, /bin/shale nie mogę potwierdzić.
  2. Co uważa się za „najlepsze praktyki” pod względem pisania skryptów powłoki, które będą działać na dowolnej platformie? (ok, to jest rodzaj otwartego)
  3. Czy jest możliwe napisanie skryptu, który próbuje użyć zsh i wraca do bash, jeśli zsh nie jest dostępny? Próbowałem umieścić dwie linie shebang, jak poniżej, ale to po prostu błąd bez bad interpreter: /bin/zsh: no such file or directory, jeśli wypróbuję to na maszynie bez Zsh.

    #!/bin/zsh

    #!/bin/bash

swrobel
źródło

Odpowiedzi:

26

Która powłoka wykonuje skrypty, gdy na początku nie ma linii shebang (#! / Path / to / shell)? Zakładam / bin / sh, ale nie mogę potwierdzić.

Jądro odmawia wykonania takich skryptów i powroty ENOEXEC, więc dokładne zachowanie zależy od programu uruchomić taki skrypt z .

  • bash 4.2.39 - używa się sam
  • busybox-ash 1.20.2 - wykorzystuje się sam
  • myślnik 0.5.7 - uruchamia / bin / sh
  • fish 1.23.1 - narzeka na ENOEXEC, a następnie obwinia niewłaściwy plik
  • AT&T ksh 93u + 2012.08.01 - używa siebie
  • mksh R40f - działa / bin / sh
  • pdksh 5.2.14 - działa / bin / sh
  • sh-heirloom 050706 - wykorzystuje się sam
  • tcsh 6.18.01 - działa / bin / sh
  • zsh 5.0.0 - działa / bin / sh
  • cmd.exe 5.1.2600 - patrzy na ciebie zabawnie.

W glibc działa execv()lub execve()po prostu zwraca ENOEXEC. Ale execvp()ukrywa ten kod błędu i automatycznie wywołuje / bin / sh. (Jest to udokumentowane w exec (3p) .)

Co uważa się za „najlepsze praktyki” pod względem pisania skryptów powłoki, które będą działać na dowolnej platformie? (ok, to jest rodzaj otwartego)

Albo trzymaj się shtylko funkcji zdefiniowanych przez POSIX lub po prostu przejdź pełną wersję (która jest powszechnie dostępna) i wspomnij o tym w swoich wymaganiach, jeśli ją rozpowszechniasz.

(Teraz, gdy o tym myślę, Perl - a może Python - byłby jeszcze bardziej przenośny, nie wspominając o lepszej składni).

Zawsze dodawaj linię shebang. Jeśli używasz bash lub zsh, użyj #!/usr/bin/env bashzamiast twardego kodowania ścieżki powłoki. (Jednak powłoka POSIX z pewnością jest w /bin/sh, więc pomiń envw tym przypadku.)

(Niestety, nawet /bin/shnie zawsze jest taki sam. Program autoconf GNU musi radzić sobie z wieloma różnymi dziwactwami ).

Czy jest możliwe napisanie skryptu, który próbuje użyć zsh i wraca do bash, jeśli zsh nie jest dostępny? Próbowałem umieścić dwie linie shebang, jak poniżej, ale to tylko błąd ze złym interpretatorem: / bin / zsh: nie ma takiego pliku lub katalogu , jeśli wypróbuję go na maszynie bez zsh.

Może istnieć tylko jedna linia shebang; wszystko po znaku nowej linii nie jest nawet czytane przez jądro i traktowane przez powłoki jako komentarz.

Jest to możliwe , aby napisać skrypt, który działa jako #!/bin/shkontrole, które są dostępne, powłoki i tras exec zsh "$0" "$@"lub exec bash "$0" "$@"w zależności od wyniku. Jednak składnia używana przez bash i zsh jest tak różna w różnych miejscach, że nie poleciłbym tego robić dla własnego zdrowia psychicznego.

grawitacja
źródło
1
w jaki sposób prześledziłeś, co faktycznie wołała każda powłoka, gdy otrzymała ENOEXEC?
swrobel
2
@SWrobel: Korzystanie strace -f -e fork,clone,execve. Niektóre pociski kontynuowały wykonywanie /bin/shpo awarii; inni sami interpretowali skrypt.
grawity
1
@SWrobel: Inną metodą jest uruchomienie skryptu, który się składa readlink /proc/$$/exe.
grawity,
2
Zobacz także odpowiedź Stéphane Chazelas za do których powłoka tłumacza uruchamia skrypt bez shebang? (duplikat pytania częściowego nr 1)
G-Man mówi „Reinstate Monica”
1
Dla cshi tcshzachowanie zależy od tego, czy skrypt zaczyna się od #(w którym to przypadku wywołują się zamiast sh, aby zinterpretować skrypt). To sięga czasów, gdy csh obsługiwał komentarze, ale nie powłokę Bourne'a, więc #była to wskazówka, że ​​był to skrypt csh.
sch
2

1) Bieżąca powłoka, w której działasz. (Bez względu na powłokę)

2) Trzymaj się tego samego typu powłoki (bash / dash / ash / csh / cokolwiek innego) i upewnij się, że twoje „obsługiwane platformy” domyślnie instalują powłokę, której chcesz używać. Spróbuj także użyć powszechnie dostępnych poleceń w systemach. Unikaj opcji specyficznych dla maszyny.

3) Tak naprawdę nie ma logiki „jeśli-to-inaczej” interpreter directive. Powinieneś określić powłokę, która powinna istnieć we wszystkich systemach, które chcesz obsługiwać ... tj. #!/bin/bashLub określić ogólną, #!/bin/sho ile skrypt jest dość ogólny we wszystkich powłokach.

TheCompWiz
źródło