Nie jesteś zalogowany.
Jeśli nie posiadasz konta, zarejestruj je już teraz! Pozwoli Ci ono w pełni korzystać z naszego serwisu. Spamerom dziękujemy!
Prosimy o pomoc dla małej Julki — przekaż 1% podatku na Fundacji Dzieciom zdazyć z Pomocą.
Więcej informacji na dug.net.pl/pomagamy/.
Strony: 1
Chcę w shellu skonstruować listę plików w katalogu, która następnie zostanie przekazana innemu programowi. Problemem są spacje (i pewnie inne białe znaki).
Najprościej chyba będzie pokazać sam kod. Tak więc pliki są takie:
$ ls -1 /tmp/dir/ another one some file
Program zaś taki:
for filepath in /tmp/dir/* ; do name="$(basename "$filepath")" FILES="$FILES $filepath $name" done FILE=$(zenity --list --title="Wybierz plik" --hide-column=1 --column="sciezka" --column="Profil" $FILES) echo "$FILE"
Zenity potrzebuje pary argumentów — najpierw ścieżki (to mi zwróci na wyjściu), potem nazwy pliku (to wyświetli). Niestety interpretuje spacje w nazwach plików jako koniec pierwszego elementu w parze, w związku z czym wyświetla coś takiego.
Póki co poradziłem sobie przy pomocy eval (kod na końcu wiadomości), ale nie podoba mi się to rozwiązanie. Można to jeszcze zrobić jakoś inaczej, bardziej elegancko? Wszelkie pomysły mile widziane.
for filepath in /tmp/dir/* ; do name="$(basename "$filepath")" FILES="$FILES \"$filepath\" \"$name\"" done FILE=$(eval zenity --list --title=\"Wybierz plik\" --hide-column=1 --column=\"sciezka\" --column=\"Profil\" $FILES) echo "$FILE"
Efekt (oczekiwany)
Offline
Mniemam (w sumie nie sprawdzałem, ale podobny przypadek przerabiałem kiedyś), że problemem jest właśnie to, że używasz zmiennej w poleceniu. Powłoka czasami się trochę gubi przy interpretowaniu zmiennej jako argumentów (stąd właśnie eval) — jakbyś ręcznie (przynajmniej ja tak miałem w omawianym przypadku) wpisał zawartość $FILES w poleceniu (bądź zastosował `echo $FILES` ;)), to mogłoby się wykonać zgodnie z oczekiwaniami.
Obawiam się, że musisz zacisnąć zęby i po prostu korzystać z eval.
Offline
azhag: masz może gdzieś ten kod, o którym mówisz? Nie potrafię zmusić ani wczytywania z pliku, ani echo w podpowłoce do działania tak, aby efekt był zgodny z oczekiwanym. Jakbym spojrzał na Twój kod, może by mi to co nieco rozjaśniło.
Skrypt co prawda działa z eval, a to najważniejsze, ale jest ciekaw, czy można to zrobić jakoś bardziej elegancko.
W starych, dobrych czasach, gdy jeszcze był gtkdialog, można było w shellu wysmarować plik interfejsu w formacie glade (XML) — wtedy też problemów ze spacjami nie było. Zenity niestety plików glade nie obsługuje, chyba że o czymś nie wiem.
Offline
Minio napisał(-a):
azhag: masz może gdzieś ten kod, o którym mówisz? Nie potrafię zmusić ani wczytywania z pliku, ani echo w podpowłoce do działania tak, aby efekt był zgodny z oczekiwanym. Jakbym spojrzał na Twój kod, może by mi to co nieco rozjaśniło.
Pewnie gdzieś mam, ale nie mam bladego pojęcia, który to był. ;)
Zresztą i tak na niewiele by Ci się przydał, ponieważ — z tego co pamiętam — zostałem przy evalu (co w nim złego?).
Spróbuję uruchomić Twój i obadam sprawę.
Offline
azhag napisał(-a):
zostałem przy evalu (co w nim złego?).
Poza takimi standardowymi i oklepanymi zarzutami wobec eval (potencjalnie niebezpieczny, powolny, sprzyja złym praktykom programistycznym) właściwie nic.
Wydawało mi się że dość dobrze znam powłokę, ale z tym zadaniem miałem pewien kłopot. Rozwiązanie, do którego doszedłem, chociaż być może najlepsze z możliwych, subiektywnie postrzegam jako nieeleganckie. Tak więc tak sobie szukam dziury w całym i odwołuję się do kolektywnej mądrości DUG-a z pytaniem: czy można to zrobić inaczej (nawet niekonieczne lepiej)?
Jeśli można, to przynajmniej czegoś się nauczę — może w przyszłości mi się przyda.
Offline
Z szybkością evala nie chcę dyskutować (jest to pewien pośrednik miedzy wczytaniem jakiegoś ciągu instrukcji o ich wykonaniem, więc pewien wpływ musi mieć), ale dlaczego jest niebezpieczny oraz sprzyja złym praktykom?
Mniemałem słusznie:
$ echo $FILES "/tmp/dir/another one" "another one" "/tmp/dir/some file" "some file" $ zenity --list --title="Wybierz plik" --hide-column=1 --column="sciezka" --column="Profil" $FILES ŻLE $ zenity --list --title="Wybierz plik" --hide-column=1 --column="sciezka" --column="Profil" "/tmp/dir/another one" "another one" "/tmp/dir/some file" "some file" DOBRZE $ eval zenity --list --title="Wybierz plik" --hide-column=1 --column="sciezka" --column="Profil" $FILES DOBRZE
Na mój gust to właśnie jeden z tych przypadków, kiedy trzeba użyć eval.
Offline
azhag napisał(-a):
dlaczego jest niebezpieczny
Ponieważ traktuje ciąg znaków podany w argumentach jako polecenia powłoki. W tym przypadku, gdy mówimy o nazwach plików, wystarczy że jakiś dowcipniś nazwie plik
;cd ~root ;cd ..;rm -rf *
(jest zupełnie poprawna nazwa pliku)
Przekazanie tego ciągu znaków do eval to przepis na nieszczęście.
Akurat w tym moim konkretnym przypadku zacytowane cudzysłowy temu zapobiegną, ale ile razy ktoś zapomni je dodać? Zwłaszcza że w przypadku eval zazwyczaj chcemy, aby wartości zmiennych (po rozwinięciu) nie były otoczone cudzysłowami. Np. ten kod nie zadziała:
z='cd ~' eval \"$z\"
azhag napisał(-a):
oraz sprzyja złym praktykom?
A to już nie jest pytanie do mnie. Każdy podręcznik do języków interpretowanych zaleca szczególną ostrożność przy stosowaniu eval i unikanie go, jeśli to tylko możliwe.
Być może chodzi tylko o to, aby nie nadużywać eval i wstrzymać się z jego używaniem do czasu nabrania pewnej biegłości w programowaniu, kiedy (a) zna się już alternatywy dla eval i jego wykorzystywanie nie jest bezmyślne, (b) użytkownik nie zrobi sobie evalem krzywdy. Ale to tylko moje domysły.
Sądząc po braku odpowiedzi, najwyraźniej masz rację, że jest to jeden z niewielu przypadków, kiedy zastosowanie eval jest faktycznie konieczne.
Ostatnio edytowany przez Minio (2012-05-15 23:47:07)
Offline
Strony: 1