Dlaczego ten skrypt działa w terminalu, ale nie z pliku?


19

Mam ten skrypt powłoki zapisany w pliku: podstawia ciąg znaków.

#!/bin/sh
html_file=$1
echo "html_file = $html_file"
substr=.pdf
pdf_file="${html_file/.html/.pdf}"
echo "pdf_file = $pdf_file"

Jeśli wkleję go do wiersza poleceń, działa dobrze:

$ html_file="/home/max/for_pauld/test_no_base64.html"
  echo "html_file = $html_file"
  substr=.pdf
  pdf_file="${html_file/.html/.pdf}"
  echo "pdf_file = $pdf_file"

daje

html_file = /home/max/for_pauld/test_no_base64.html
pdf_file = /home/max/for_pauld/test_no_base64.pdf

To jest wynik z echa powyżej - działa zgodnie z przeznaczeniem.

Ale kiedy wywołuję skrypt, z

$ saucer "/home/max/for_pauld/test_no_base64.html"

Otrzymuję ten wynik:

html_file = /home/max/for_pauld/test_no_base64.html
/home/max/bin/saucer: 5: /home/max/bin/saucer: Bad substitution

Czy mój skrypt używa innej wersji bash czy coś takiego? Czy muszę zmienić linię shebang?


6
Ta ekspansja parametrów to bashism (no, non-POSIX): zmień swój shebang.
jasonwryan

Dzięki! To się udało. Myślę, że jestem trochę zamglony na różnicę między shi bash. Przeczytam o tym. Jeśli zechcesz zamienić komentarz w odpowiedź, oznaczę go poprawnie.
Max Williams,

Dałem kleszczowi Książęowi za szczegółową odpowiedź, ale i tak dzięki.
Max Williams,

2
@ MaxWilliams: w skrócie, sh jest oryginalną powłoką Bourne'a. Wszystkie kompatybilne skrypty powinny być napisane dla sh. Ale wiele kolejnych powłok (np. Bash, powłoka Bourne Again) są „prawie kompatybilne” i dodają wiele dodatkowych zalet. Takich jak zastąpienie, którego użyłeś. W dzisiejszych czasach korzystanie z funkcji posix jest całkiem bezpieczne, ale należy pamiętać, że przenośność zależy nawet od węższego zestawu (tj. Tylko sh). Ogólnie używaj: #!/usr/bin/env bashjako shebang i używaj odpowiednio zdefiniowanych podstawień, jak chcesz, ale z zastrzeżeniami dotyczącymi przenośności. I przeczytaj: unix.stackexchange.com/a/48787/27616
Olivier Dulac

Odpowiedzi:


37

Co to jest sh

sh(lub Shell Command Language) to język programowania opisany przez standard POSIX . Posiada wiele wdrożeń ( ksh88, dash...). bashmożna również uznać za wdrożenie sh(patrz poniżej).

Ponieważ shspecyfikacja, a nie implementacja, /bin/shjest dowiązaniem symbolicznym (lub dowiązaniem twardym) do rzeczywistej implementacji w większości systemów POSIX.

Co to jest bash

bashzaczęło się jako shimplementacja kompatybilna (chociaż wyprzedza standard POSIX o kilka lat), ale z czasem zyskała wiele rozszerzeń. Wiele z tych rozszerzeń może zmienić zachowanie prawidłowych skryptów powłoki POSIX, więc samo w sobie bashnie jest prawidłową powłoką POSIX. Jest to raczej dialekt języka powłoki POSIX.

bashobsługuje --posixprzełącznik, co czyni go bardziej zgodnym z POSIX. Próbuje również naśladować POSIX, jeśli zostanie wywołany jako sh.

sh = bash?

Przez długi czas /bin/shwskazywał /bin/bashna większość systemów GNU / Linux. W rezultacie prawie bezpiecznie stało się ignorowanie różnicy między nimi. Ale to zaczęło się ostatnio zmieniać.

Niektóre popularne przykłady systemów, na które /bin/shnie wskazuje /bin/bash(a niektóre z nich /bin/bashmogą nawet nie istnieć) to:

  1. Nowoczesne systemy Debian i Ubuntu, shdo dashktórych domyślnie prowadzi dowiązanie symboliczne ;
  2. Busybox , który zwykle jest uruchamiany podczas uruchamiania systemu Linux jako część initramfs. Wykorzystuje ashimplementację powłoki.
  3. BSD i ogólnie wszelkie systemy inne niż Linux. Używa OpenBSD pdksh, potomek powłoki Korn. FreeBSD shjest potomkiem oryginalnej powłoki UNIX Bourne. Solaris ma swój własny, shktóry przez długi czas nie był zgodny z POSIX; darmowa implementacja jest dostępna z projektu Heirloom .

Jak możesz dowiedzieć się, na co /bin/shwskazuje twój system?

Komplikacja polega na tym, że /bin/shmoże to być dowiązanie symboliczne lub dowiązanie twarde. Jeśli jest to łącze symboliczne, przenośnym sposobem jego rozwiązania jest:

% file -h /bin/sh
/bin/sh: symbolic link to bash

Jeśli jest to twardy link, spróbuj

% find -L /bin -samefile /bin/sh
/bin/sh
/bin/bash

W rzeczywistości -Lflaga obejmuje zarówno dowiązania symboliczne, jak i dowiązania twarde, ale wadą tej metody jest to, że nie jest przenośna - POSIX nie wymaga find obsługi -samefileopcji, chociaż zarówno GNU find, jak i FreeBSD ją obsługują.

Linia Shebang

Ostatecznie to Ty decydujesz, którego użyć, pisząc wiersz «shebang».

Na przykład

#!/bin/sh

użyje sh(i cokolwiek innego, co wskaże),

#!/bin/bash

użyje, /bin/bashjeśli jest dostępny (i zakończy się niepowodzeniem z komunikatem o błędzie, jeśli nie jest). Oczywiście możesz również określić inną implementację, np

#!/bin/dash

Którego użyć

W przypadku moich własnych skryptów wolę shz następujących powodów:

  • jest ustandaryzowany
  • jest o wiele prostszy i łatwiejszy do nauczenia
  • jest przenośny w różnych systemach POSIX - nawet jeśli tak się nie dzieje bash, trzeba je miećsh

Istnieją również zalety korzystania z niego bash. Jego funkcje sprawiają, że programowanie jest wygodniejsze i podobne do programowania w innych współczesnych językach programowania. Należą do nich takie zmienne lokalne i tablice o zasięgu. Zwykły shto bardzo minimalistyczny język programowania.


Dzięki za szczegółową odpowiedź: używam Linux Mint, który jest oparty na Debianie i /bin/shrzeczywiście jest dowiązaniem symbolicznym /bin/dash.
Max Williams,

Jeśli chcesz zastosować się do POSIX sh, najlepiej całkowicie pomiń shebang: jeśli pierwszy wiersz pliku poleceń powłoki zaczyna się od znaków „#!”, Wyniki są nieokreślone pubs.opengroup.org/onlinepubs/009695399/ narzędzia /…
Daniel Jour

4
@DanielJour Gdyby jakikolwiek system uniksowy porzucił zwykłe wsparcie dla shebangów, zepsułoby to tak wiele rzeczy, że praktycznie byłoby bezużyteczne. Jest to de facto standard, nawet jeśli nie jest określony w POSIX. Jedynym faktycznym problemem dotyczącym zgodności jest to, że ścieżka do tłumaczy może się różnić.
Barmar

23

Dodając do doskonałej odpowiedzi z @ Hunter.S. Thompson, chciałbym zauważyć, że nieprzenośną częścią skryptu jest

pdf_file="${html_file/.html/.pdf}"

Jest ${variable/search/replace}to rozszerzenie GNU. Ale możesz tego łatwo uniknąć dzięki czystemu POSIX:

pdf_file="${html_file%.html}".pdf

Po Hunterze jest to lepsze rozwiązanie niż zmiana shebang na #! /bin/bash


Dzięki - zgadzam się, że jest to „czystsza” poprawka, ale wolę bash ładowany shebang, ponieważ rutynowo używam tego w terminalu (domyślnie) i łatwiej jest mieć skrypty robiące to samo, co zwykłe wiersz poleceń.
Max Williams,

1
@MaxWilliams Oczywiście nie ma problemu. Dotyczyło to głównie bazy danych pytań i odpowiedzi.
Philippos,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.