W Ubuntu 16.04.3 mam bardzo prosty skrypt bash:
test.sh
[[ 0 == 0 ]] && result="true" || result="false"
echo $result
echo $USER $SHELL $0
Kiedy nazywam to jako użytkownik inny niż root me
lub jako root
, działa zgodnie z oczekiwaniami. Jeśli użyję sudo ./test.sh
, narzeka na błąd składniowy:
$ ./test.sh
true
me /bin/bash ./test.sh
$ sudo su
# ./test.sh
true
root /bin/bash ./test.sh
# exit
$ sudo ./test.sh
./test.sh: 1: ./test.sh: [[: not found
false
root /bin/bash ./test.sh
Co może być tego przyczyną? Jak mogę to naprawić, aby me
można było używać tego skryptu zarówno normalnie, jak i za pomocą sudo
?
sudo su
. Po prostu uruchomsudo -i
lubsudo -s
zamiast tego.sudo -i
zmienia lokalizację na/root
.sudo su
lubsudo -s
nie zmieniaj lokalizacji katalogu.-s
.Odpowiedzi:
Każdy skrypt zaczyna się od Shebang , bez niego powłoka uruchamiająca skrypt nie wie, który interpreter powinien uruchomić twój skrypt 1, i może - tak jak w tym przypadku
sudo ./script.sh
- uruchomić go, zsh
którym w Ubuntu 16.04 jest powiązanydash
. Wyrażenie warunkowe[[
jestbash
komenda związek , więcdash
nie wiem, jak sobie z tym poradzić i rzuca napotkany błąd.Rozwiązaniem jest dodanie
jako pierwszy wiersz skryptu. Możesz uzyskać ten sam wynik, gdy nazywasz go jawnie
sudo bash ./script.sh
, ale szlaban jest dobrym rozwiązaniem.Aby sprawdzić, która powłoka uruchamia skrypt, dodaj
echo $0
do niego. To nie to samo, coecho $SHELL
cytowanie wiki.archlinux.org :1: Jak rozpoczęła
./test.sh
siębash
po prostu założyćbash
, to samo tyczy sięsudo su
podpowłoce.źródło
/bin/sh
.echo $0
Daje mi nazwę skryptu:./test.sh
)/proc/$$/exe
wskazuje. Ponadto można przetestować różne zmienne, jak$BASH_VERSION
,$ZSH_VERSION
itp (ale kreska nie ustala żadnych takich zmienna)Jak wyjaśnił @dessert , problem polega na tym, że twój skrypt nie ma linii shebang . Bez shebang,
sudo
domyślnie będzie próbował uruchomić plik przy użyciu/bin/sh
. Nigdzie nie mogłem go udokumentować, ale potwierdziłem, sprawdzającsudo
kod źródłowy, w którym znalazłem następujące informacje w plikupathnames.h
:Oznacza to „ustaw, jeśli zmienna
_PATH_BSHELL
nie jest zdefiniowana, ustaw ją na/bin/sh
”. Następnie wconfigure
skrypcie zawartym w źródłowym pliku archiwalnym mamy:Pętla ta wygląda na
/bin/bash
,/usr/bin/sh
,/sbin/sh
,/usr/sbin/sh
i/bin/ksh
, a następnie ustawia_PATH_BSHELL
się w zależności od tego stwierdzono pierwszy . Ponieważ/bin/sh
był pierwszy na liście i istnieje,_PATH_BSHELL
jest ustawiony na/bin/sh
. Wynikiem tego wszystkiego jest to, że domyślną powłoką jestsudo
chyba, że zdefiniowano inaczej/bin/sh
.Tak więc
sudo
domyślnie uruchomi się za pomocą,/bin/sh
a na Ubuntu, który jest dowiązaniem symbolicznym dodash
minimalnej powłoki zgodnej z POSIX:[[
Konstrukt funkcja atakujących, nie jest zdefiniowane przez standard POSIX i nie są rozumiane przezdash
:Szczegółowo w trzech wywołaniach, które próbowałeś:
./test.sh
Nie
sudo
; w przypadku braku linii shebang, twoja powłoka spróbuje wykonać sam plik. Ponieważ działaszbash
, będzie to działać skuteczniebash ./test.sh
i działać.sudo su
a następnie./test.sh
.Tutaj zaczynasz nową powłokę dla użytkownika
root
. Będzie to dowolna powłoka zdefiniowana w$SHELL
zmiennej środowiskowej dla tego użytkownika, a na Ubuntu domyślną powłoką roota jestbash
:sudo ./test.sh
Tutaj pozwalasz
sudo
na bezpośrednie wykonanie polecenia. Ponieważ jego domyślna powłoka jest taka,/bin/sh
jak wyjaśniono powyżej, powoduje to uruchomienie skryptu/bin/sh
, co jestdash
i kończy się niepowodzeniem, ponieważdash
nie rozumie[[
.Uwaga : szczegóły dotyczące
sudo
ustawień domyślnej powłoki wydają się nieco bardziej złożone. Próbowałem zmienić pliki wymienione w mojej odpowiedzi, aby wskazywały,/bin/bash
alesudo
nadal domyślnie/bin/sh
. Dlatego w kodzie źródłowym muszą znajdować się inne miejsca, w których zdefiniowana jest domyślna powłoka. Niemniej jednak główny punkt (którysudo
domyślnie jestsh
) nadal obowiązuje.źródło
/bin/sh
z komunikatu o błędzie - co jeszcze może być? Odpowiedź na to pytanie jest piękna w tym, z czego korzysta sudo · SO , patrz takżeman sudo
sekcja WYKONYWANIE POLECEŃ . Okazuje się,sudo
że nie używa pośredniej powłoki !execve
wywołania systemowego, która domyślnie jest ustawiona nash
. I nie, powłoki pośrednie nie mają znaczenia, nie chodzi o powłokę uruchamiającą polecenie, ale o interpreter powłoki używany do odczytu podanego skryptu powłoki. Więc nie, nie uruchamia powłoki pośredniej, ale nadal potrzebuje interpretera powłoki dla skryptów powłoki.