Bez względu na to, jak to rozwiążesz, nadal niewiele zrobi. cdMa tylko wpływ wewnątrz bash -cskorupy.
Kusalananda
Podaję tylko minimalny przykład samego pytania, nie jest to działające rozwiązanie mojego prawdziwego problemu, którym jest unix.stackexchange.com/a/269080/674, a ponadto w podanym ciągu poleceń sudo bash -cmam zmienne rozszerzenie do ścieżka, która może zawierać białe znaki.
Tim
Odpowiedzi:
13
W tym kodzie nie ma podziału słów (jak w przypadku funkcji, która dzieli zmienne przy niecytowanych rozszerzeniach), ponieważ $myvarnie jest ona cytowana.
Istnieje jednak usterka $myvarpolegająca na wstrzykiwaniu poleceń, która jest rozszerzana przed przekazaniem do bash. Jego treść jest interpretowana jako kod bashowy!
Spacje w nich spowodują przekazanie kilku argumentów cd, nie z powodu podziału słów , ale dlatego, że zostaną one przeanalizowane jako kilka tokenów w składni powłoki. Z wartością bye;reboot, to uruchomi się ponownie!
Tutaj chciałbyś:
sudo bash -c 'cd -P -- "$1"' bash "$myvar"
(gdzie można przekazać zawartość $myvarjako pierwszy argument tego skryptu inline; notatka jak zarówno $myvari $1były notowane odpowiednio dla swoich skorupach, aby zapobiec IFS-word-rozszczepienia (i globbing)).
Oczywiście nie osiągniesz niczego użytecznego, uruchamiając tylkocd w tym wbudowanym skrypcie (innym niż sprawdzenie, czy rootmożna cdtam wejść). Prawdopodobnie chcesz, aby ten skrypt cdtam był, a następnie zrób tam coś innego, na przykład:
Jeśli chodziło o to, sudoaby móc przejść cddo katalogu, do którego inaczej nie masz dostępu, to tak naprawdę nie może działać.
sudo sh -c 'cd -P -- "$1" && exec bash' sh "$myvar"
uruchomi interaktywny bashz bieżącym katalogiem w $myvar. Ale ta powłoka będzie działać jako root.
Mógłbyś:
sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
Aby uzyskać nieuprzywilejowaną interaktywność bashz bieżącym katalogiem $myvar, ale jeśli nie masz uprawnień do cdtego katalogu, nie będziesz w stanie nic zrobić w tym katalogu, nawet jeśli jest to twój bieżący katalog roboczy.
$ myvar=/var/spool/cron/crontabs
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ ls
ls: cannot open directory '.':Permission denied
Wyjątkiem może być posiadanie uprawnień do wyszukiwania do samego katalogu, ale nie do jednego ze składników katalogu jego ścieżki:
$ myvar=1/2
$ mkdir -p "$myvar"
$ chmod 01
$ cd 1/2
cd: permission denied:1/2
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ pwd
/home/stephane/1/2
bash-4.4$ mkdir 3
bash-4.4$ ls
3
bash-4.4$ cd "$PWD"
bash: cd:/home/stephane/1/2:Permission denied
¹ ściśle mówiąc, w przypadku wartości $myvarpodobnych $(seq 10)(dosłownie), po rozszerzeniu tego podstawiania poleceń przez bash powłokę zacząłoby się dzielenie słówroot
Pojawiła się nowa magia cytowania (bash 4.4), która pozwala ci bardziej bezpośrednio robić to, co chcesz. W zależności od większego kontekstu użycie jednej z innych technik może być lepsze, ale działa w tym ograniczonym kontekście.
ARGUMENT jest drukowany w formacie, który można ponownie wykorzystać jako dane wejściowe powłoki, unikając znaków niedrukowalnych z proponowaną $''składnią POSIX .
GNU printfbędzie tam wywoływane tylko w systemach GNU, a jeśli $(printf '%q' "$myvar")zostanie uruchomione w powłoce, w której printfnie jest wbudowane. Większość pocisków ma printfobecnie wbudowane. Nie wszyscy jednak obsługują, %qa kiedy to robią, cytują rzeczy w formacie obsługiwanym przez odpowiednią powłokę, co niekoniecznie musi być takie samo, jak rozumiane przez bash. Właściwie bashnic printfnie zacytować rzeczy prawidłowo nawet sama dla niektórych wartości $myvarw niektórych lokalizacjach.
Stéphane Chazelas
Z bash-4.3co najmniej, że nadal jest to usterka wtrysku komenda z myvar=$'\xa3``reboot`\xa3`' In A zh_HK.big5hkscs locale na przykład.
Stéphane Chazelas,
3
Przede wszystkim, jak zauważyli inni, twoje cdpolecenie jest bezużyteczne, ponieważ dzieje się to w kontekście powłoki, która natychmiast wychodzi. Ale ogólnie pytanie ma sens. Potrzebny jest sposób na zacytowanie powłoki dowolnego łańcucha , aby można go było używać w kontekście, w którym będzie on interpretowany jako łańcuch cytowany w powłoce. Mam taki przykład na stronie ze sztuczkami sh :
quote (){ printf %s\\n "$1"| sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/'/";}
To, co sugeruje Stéphane Chazelas, jest zdecydowanie najlepszym sposobem na zrobienie tego. Podam tylko odpowiedź, jak bezpiecznie cytować ze składnią rozszerzania parametrów w przeciwieństwie do korzystania z sedpodprocesu, jak w odpowiedzi R.
Pojedyncze cudzysłowy nie będą tutaj działać, ponieważ wtedy twoja zmienna nie zostanie rozwinięta. Jeśli masz pewność, że zmienna dla twojej ścieżki jest odkażona, najprostszym rozwiązaniem jest po prostu dodać cudzysłowy wokół wynikowego rozszerzenia, gdy znajdzie się w nowej powłoce bash:
Nadal podatność na wstrzykiwanie poleceń, jak dla wartości $myvarpodobnych $(reboot)lub"; reboot; #
Stéphane Chazelas
1
użycie sudo bash -c "cd -P -- '$myvar'"ograniczyłoby problem do tylko tych wartości, $myvar które zawierają znaki pojedynczego cudzysłowu, co byłoby łatwiejsze do oczyszczenia.
cd
Ma tylko wpływ wewnątrzbash -c
skorupy.sudo bash -c
mam zmienne rozszerzenie do ścieżka, która może zawierać białe znaki.Odpowiedzi:
W tym kodzie nie ma podziału słów (jak w przypadku funkcji, która dzieli zmienne przy niecytowanych rozszerzeniach), ponieważ
$myvar
nie jest ona cytowana.Istnieje jednak usterka
$myvar
polegająca na wstrzykiwaniu poleceń, która jest rozszerzana przed przekazaniem dobash
. Jego treść jest interpretowana jako kod bashowy!Spacje w nich spowodują przekazanie kilku argumentów
cd
, nie z powodu podziału słów , ale dlatego, że zostaną one przeanalizowane jako kilka tokenów w składni powłoki. Z wartościąbye;reboot
, to uruchomi się ponownie!Tutaj chciałbyś:
(gdzie można przekazać zawartość
$myvar
jako pierwszy argument tego skryptu inline; notatka jak zarówno$myvar
i$1
były notowane odpowiednio dla swoich skorupach, aby zapobiec IFS-word-rozszczepienia (i globbing)).Lub:
(gdzie przekazujesz zawartość
$myvar
zmiennej środowiskowej).Oczywiście nie osiągniesz niczego użytecznego, uruchamiając tylko
cd
w tym wbudowanym skrypcie (innym niż sprawdzenie, czyroot
możnacd
tam wejść). Prawdopodobnie chcesz, aby ten skryptcd
tam był, a następnie zrób tam coś innego, na przykład:Jeśli chodziło o to,
sudo
aby móc przejśćcd
do katalogu, do którego inaczej nie masz dostępu, to tak naprawdę nie może działać.uruchomi interaktywny
bash
z bieżącym katalogiem w$myvar
. Ale ta powłoka będzie działać jakoroot
.Mógłbyś:
Aby uzyskać nieuprzywilejowaną interaktywność
bash
z bieżącym katalogiem$myvar
, ale jeśli nie masz uprawnień docd
tego katalogu, nie będziesz w stanie nic zrobić w tym katalogu, nawet jeśli jest to twój bieżący katalog roboczy.Wyjątkiem może być posiadanie uprawnień do wyszukiwania do samego katalogu, ale nie do jednego ze składników katalogu jego ścieżki:
¹ ściśle mówiąc, w przypadku wartości
$myvar
podobnych$(seq 10)
(dosłownie), po rozszerzeniu tego podstawiania poleceń przezbash
powłokę zacząłoby się dzielenie słówroot
źródło
Pojawiła się nowa magia cytowania (bash 4.4), która pozwala ci bardziej bezpośrednio robić to, co chcesz. W zależności od większego kontekstu użycie jednej z innych technik może być lepsze, ale działa w tym ograniczonym kontekście.
źródło
Jeśli nie możesz zaufać zawartości
$myvar
, jedynym rozsądnym podejściem jest użycie GNUprintf
do utworzenia jego ucieczkowej wersji:Jak
printf
mówi strona podręcznika :źródło
printf
będzie tam wywoływane tylko w systemach GNU, a jeśli$(printf '%q' "$myvar")
zostanie uruchomione w powłoce, w którejprintf
nie jest wbudowane. Większość pocisków maprintf
obecnie wbudowane. Nie wszyscy jednak obsługują,%q
a kiedy to robią, cytują rzeczy w formacie obsługiwanym przez odpowiednią powłokę, co niekoniecznie musi być takie samo, jak rozumiane przezbash
. Właściwiebash
nicprintf
nie zacytować rzeczy prawidłowo nawet sama dla niektórych wartości$myvar
w niektórych lokalizacjach.bash-4.3
co najmniej, że nadal jest to usterka wtrysku komenda zmyvar=$'\xa3``reboot`\xa3`'
In A zh_HK.big5hkscs locale na przykład.Przede wszystkim, jak zauważyli inni, twoje
cd
polecenie jest bezużyteczne, ponieważ dzieje się to w kontekście powłoki, która natychmiast wychodzi. Ale ogólnie pytanie ma sens. Potrzebny jest sposób na zacytowanie powłoki dowolnego łańcucha , aby można go było używać w kontekście, w którym będzie on interpretowany jako łańcuch cytowany w powłoce. Mam taki przykład na stronie ze sztuczkami sh :Dzięki tej funkcji możesz następnie:
źródło
To, co sugeruje Stéphane Chazelas, jest zdecydowanie najlepszym sposobem na zrobienie tego. Podam tylko odpowiedź, jak bezpiecznie cytować ze składnią rozszerzania parametrów w przeciwieństwie do korzystania z
sed
podprocesu, jak w odpowiedzi R.Dane wyjściowe tego skryptu to:
źródło
Tak, istnieje podział słów.
Cóż, technicznie rzecz biorąc, dzielenie wiersza poleceń podczas bash parsowania linii.
Zacznijmy od właściwej wyceny:
Najprostszym (i niepewnym) rozwiązaniem, aby polecenie działało tak, jak sądzę, będzie to potrzebne:
Potwierdźmy, co się stanie (zakładając
myvar="/path to/my directory"
):Jak widać, łańcuch ścieżki został podzielony na spacje. I:
Nie jest podzielony.
Jednak polecenie (jak napisano) jest niepewne. Lepsze wykorzystanie:
To ochroni płytę CD przed plikami rozpoczynającymi się od myślnika (-) lub następujących łączy, które mogą prowadzić do problemów.
To zadziała, jeśli możesz zaufać, że ciąg znaków
$myvar
jest ścieżką.Jednak „wstrzyknięcie kodu” jest nadal możliwe, ponieważ „wykonujesz ciąg”:
Potrzebujesz silniejszego cytowania łańcucha, takiego jak:
Jak widać powyżej, wartość nie została zinterpretowana, a jedynie użyta jako
"$1'
.Teraz możemy (bezpiecznie) korzystać z sudo:
Jeśli jest kilka argumentów, możesz użyć:
źródło
Pojedyncze cudzysłowy nie będą tutaj działać, ponieważ wtedy twoja zmienna nie zostanie rozwinięta. Jeśli masz pewność, że zmienna dla twojej ścieżki jest odkażona, najprostszym rozwiązaniem jest po prostu dodać cudzysłowy wokół wynikowego rozszerzenia, gdy znajdzie się w nowej powłoce bash:
źródło
$myvar
podobnych$(reboot)
lub"; reboot; #
sudo bash -c "cd -P -- '$myvar'"
ograniczyłoby problem do tylko tych wartości,$myvar
które zawierają znaki pojedynczego cudzysłowu, co byłoby łatwiejsze do oczyszczenia.