Jak mogę zdezynfekować lub uciec od ścieżek bezwzględnych zwróconych przez realpath lub readlink?

9

realpathi readlinkzwracaj ścieżki bezwzględne:

+akiva@X230:~$ realpath ZannaIsAwesome
/home/akiva/ZannaIsAwesome

Z taką ścieżką łatwo sobie poradzić. Jednak coś takiego będzie miało pewne problemy:

wprowadź opis zdjęcia tutaj

Na przykład:

wprowadź opis zdjęcia tutaj

Tak więc nazwa taka musi zostać zdezynfekowana, aby móc przekazać ją innym poleceniom. Przypadkiem użycia może być coś takiego:

+a@X230:~/\e[92mM@r|< $hu+'|'|_e|\|\|0rth [`-_-"]$ bacon=$(realpath pullingATerdon)
+a@X230:~$ vim $bacon 

Nie trzeba dodawać, vim $baconże nie będzie działać zgodnie z oczekiwaniami.

Co mogę zrobić, aby zdezynfekować tę ścieżkę bezwzględną, aby działała z innymi poleceniami?

Akiva
źródło
3
Zawsze vim "$bacon"
podawaj
@steeldriver Dlaczego tak jest?
Akiva
3
Bo jeśli tego nie zrobisz,
wpadniesz

Odpowiedzi:

12

Jak to zrobić poprawnie

Przede wszystkim zawsze podawaj swoje zmienne . To, co próbujesz zrobić, działa dobrze, jeśli odpowiednio go zacytujesz:

$ pwd
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]
$ ls
pullingATerdon

Zachowałem dziwną nazwę pliku, którą wybrałeś ( chociaż nie mam pojęcia, dlaczego ją wybrałeś ) dla zachowania spójności.

Teraz przypiszmy ścieżkę pullingATerdondo zmiennej, a następnie spróbuj otworzyć plik:

$ bacon="$(realpath pullingATerdon)"
$ echo "$bacon"
/home/terdon/foo/\e[92mM@r|< +'|'|_e|\|\|0rth [`-_-"]/pullingATerdon
$ ls $bacon
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

To się nie powiedzie, zgodnie z oczekiwaniami. Ale jeśli teraz podamy to poprawnie:

$ ls -l "$bacon"
-rw-r--r-- 1 terdon terdon 0 Mar 14 23:15 '/home/terdon/foo/\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]/pullingATerdon'

Działa zgodnie z oczekiwaniami. I tak, możesz także otworzyć ścieżkę w (właściwym) edytorze: emacs "$bacon"będzie działać dobrze. OK, podobnie będzie vimi cokolwiek innego. Twój wybór redaktora, choć niefortunny, nie ma znaczenia.


Dlaczego twój zawiódł

Szybkim sposobem na prześledzenie, co faktycznie się wydarzyło w twoim przypadku, jest użycie set -x(wyłączenie go ponownie za pomocą set +x), co powoduje, że powłoka wypisuje każde polecenie, które uruchomi przed uruchomieniem. włącz komunikaty debugowania powłoki za pomocą set -x:

$ set -x
$ /bin/ls $bacon 
+ ls '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
ls: cannot access '+'\''|'\''|_e|\|\|0rth': No such file or directory
ls: cannot access '[`-_-"]/pullingATerdon': No such file or directory
'/home/terdon/foo/\e[92mM@r|<':

To pokazuje nam, że lszostał uruchomiony z trzech oddzielnych argumenty '/home/terdon/foo/\e[92mM@r|<', '+'\''|'\''|_e|\|\|0rth'i '[`-_-"]/pullingATerdon'. Dzieje się tak, ponieważ powłoka wykonuje dzielenie słów i rozwijanie globu na ciągach niecytowanych. W tym przypadku problemem jest dzielenie słów, ponieważ powłoka widziała spacje na ścieżce i odczytywała każdy ciąg oddzielony spacją jako osobny argument.

mkdirPrzykładem jest nieco inna, ale to dlatego, że jesteś pokazując nam się komunikat o błędzie z drugim wywołaniu polecenia. Wydaje mi się, że raz go wypróbowałeś, a następnie uruchomiłeś go po raz drugi, aby uzyskać wynik swojego pytania. Przy pierwszym uruchomieniu wyglądałby tak:

$ mkdir $(realpath pullingATerdon)
++ realpath pullingATerdon
+ mkdir '/home/terdon/foo/\e[92mM@r|<' '+'\''|'\''|_e|\|\|0rth' '[`-_-"]/pullingATerdon'
mkdir: cannot create directory ‘[`-_-"]/pullingATerdon’: No such file or directory

Ponownie spróbuje utworzyć trzy katalogi, a nie jeden, z powodu podziału słów. Najpierw utworzył (z powodzeniem) katalog /home/terdon/foo/\e[92mM@r|<:

$ ls -l /home/terdon/foo/
total 8
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|<'
drwxr-xr-x 3 terdon terdon 4096 Mar 15 00:20 '\e[92mM@r|< +'\''|'\''|_e|\|\|0rth [`-_-"]'

Następnie również pomyślnie utworzył katalog o nazwie +'|'|_e|\|\|0rthw bieżącym katalogu:

$ ls -l
total 4
drwxr-xr-x 2 terdon terdon 4096 Mar 15 00:37 '+'\''|'\''|_e|\|\|0rth'
-rw-r--r-- 1 terdon terdon    0 Mar 15 00:36  pullingATerdon

A następnie próbował utworzyć katalog [`-_-"]/pullingATerdon. Nie powiodło się, ponieważ mkdirdomyślnie nie tworzy podkatalogów (może, jeśli go uruchomisz -p):

$ mkdir baz/bar
mkdir: cannot create directory baz/bar’: No such file or directory

Ponieważ ciąg niecytowany zawierał /, mkdiruważany za ścieżkę dwóch katalogów, próba znalezienia pierwszego i nie powiodła się.

Dlatego się nie udało, ale to, co się stało, jest bardziej skomplikowane. Ciąg użyłeś jest rzeczywiście glob powłoki, konkretnie zakres glob , który pasuje do wszystkich plików w bieżącym katalogu, którego nazwa jest jednym z 5 znaków `, -, _lub ". Ponieważ nie masz takich plików w bieżącym katalogu, glob nie pasuje do niczego i, podobnie jak domyślne zachowanie w bash, zwraca się:

$ echo "[\`-_-\"]/pullingATerdon"  ## some escaping is needed here
+ echo '[`-_-"]/pullingATerdon'    ## but it echoes the right thing
[`-_-"]/pullingATerdon             ## and matches nothing, so returns itself.

Aby to wyjaśnić, oto co się stanie, jeśli podasz glob, który pasuje do czegoś:

$ echo [p]*   ## any filename starting with a p
pullingATerdon
$ echo "[p]*" ## the string "[p]*"
[p]*

Niecytowany [p*]jest rozwijany do listy pasujących nazw plików (w tym przypadku tylko jednej) i do tego jest przekazywany echo. To kolejny powód, dla którego powinieneś cytować wszystkie rzeczy.

Wreszcie rzeczywisty błąd, który wyświetlasz, pojawia się od drugiego uruchomienia polecenia i kończy się niepowodzeniem na pierwszym etapie podczas próby utworzenia /home/terdon/foo/\e[92mM@r|<, ponieważ poprzednie wywołanie utworzyło już ten katalog.


Mówiąc bardziej ogólnie, za każdym razem, gdy pracujesz z dowolnymi nazwami plików, zawsze używaj globów powłoki. Takie rzeczy:

for file in *; do command "$file"; done

To zadziała dla dowolnej nazwy pliku. Bez względu na to, co się zawiera. W powyższym przykładzie mogłeś:

emacs /home/terdon/*92mM*/pullingATerdon

Wykona to każdy glob, który jednoznacznie identyfikuje plik docelowy. W ten sposób nie musisz się martwić o znaki specjalne i możesz po prostu pozwolić powłoce sobie z nimi poradzić.


Kilka przydatnych odniesień:

  1. Jak mogę znaleźć i bezpiecznie obsługiwać nazwy plików zawierające znaki nowej linii, spacje lub oba? : Jedno z najczęściej zadawanych pytań na doskonałej Wiki Greya Cat.

  2. Skutki bezpieczeństwa zapomnienia o cytowaniu zmiennej w powłokach bash / POSIX : ten sam post, do którego odwoływałem się na początku tej odpowiedzi. Świetne i bardzo szczegółowe wyjaśnienie wszystkich rzeczy, które mogą pójść nie tak, jeśli nie podasz poprawnie zmiennych zmiennych powłoki.

  3. Dlaczego mój skrypt powłoki dusi się spacjami lub innymi znakami specjalnymi? : wszystko, co kiedykolwiek chciałeś wiedzieć o obsłudze dowolnych nazw plików w powłoce.

  4. Kiedy konieczne jest podwójne cytowanie? : Więcej informacji o cudzysłowach i zmiennych, a szczególnie o kilku przypadkach, w których nie trzeba ich cytować

terdon
źródło