Chcę używać find
do znajdowania plików w zestawie folderów ograniczonych symbolami wieloznacznymi, ale tam, gdzie w nazwie ścieżki są spacje.
Z linii poleceń jest to łatwe. Wszystkie poniższe przykłady działają.
find te*/my\ files/more -print
find te*/'my files'/more -print
find te*/my' 'files/more -print
Znajdą one na przykład pliki terminal/my files/more
i tepid/my files/more
.
Potrzebuję tego jednak, aby był częścią skryptu; potrzebuję czegoś takiego:
SEARCH='te*/my\ files/more'
find ${SEARCH} -print
Niestety, cokolwiek robię, nie jestem w stanie mieszać symboli wieloznacznych i spacji w find
poleceniu w skrypcie. Powyższy przykład zwraca następujące błędy (zwróć uwagę na nieoczekiwane podwojenie odwrotnego ukośnika):
find: ‘te*/my\\’: No such file or directory
find: ‘files/more’: No such file or directory
Próba użycia cytatów również się nie udaje.
SEARCH="te*/'my files'/more"
find ${SEARCH} -print
Zwraca następujące błędy, ignorując znaczenie cudzysłowów:
find: ‘te*/'my’: No such file or directory
find: ‘files'/more’: No such file or directory
Oto jeszcze jeden przykład.
SEARCH='te*/my files/more'
find ${SEARCH} -print
Zgodnie z oczekiwaniami:
find: ‘te*/my’: No such file or directory
find: ‘files/more’: No such file or directory
Każda odmiana, którą próbowałem, zwraca błąd.
Mam obejście, które jest potencjalnie niebezpieczne, ponieważ zwraca zbyt wiele folderów. Konwertuję wszystkie spacje na znak zapytania (jednoznakowy symbol wieloznaczny) w następujący sposób:
SEARCH='te*/my files/more'
SEARCH=${SEARCH// /?} # Convert every space to a question mark.
find ${SEARCH} -print
Jest to odpowiednik:
find te*/my?files/more -print
Zwraca to nie tylko prawidłowe foldery, ale także terse/myxfiles/more
, czego nie powinno.
Jak mogę osiągnąć to, co próbuję zrobić? Google mi nie pomogło :(
SEARCH: command not found
wykonanie poleceniafind -print
.find "${SEARCH}" -print
?te*/'my files'/more
.Odpowiedzi:
Dokładnie to samo polecenie powinno działać poprawnie w skrypcie:
Jeśli potrzebujesz mieć ją jako zmienną, staje się ona nieco bardziej złożona:
OSTRZEŻENIE:
Używanie w
eval
ten sposób nie jest bezpieczne i może spowodować wykonanie dowolnego i potencjalnie szkodliwego kodu, jeśli nazwy plików mogą zawierać określone znaki. Szczegółowe informacje można znaleźć w bash FAQ 48 .Lepiej podać ścieżkę jako argument:
Innym podejściem jest
find
całkowite unikanie i korzystanie z rozszerzonych funkcji globowania i globów bash:Opcja
globstar
bash umożliwia**
dopasowanie rekurencyjne:Aby działał w 100% jak znajdź i dołącz pliki dot (pliki ukryte), użyj
Możesz nawet
echo
je bezpośrednio bez pętli:źródło
Co powiesz na tablice?
(*)
rozwija się do tablicy wszystkiego, co pasuje do znaku wieloznacznego. I"${SEARCH[@]}"
rozwija się do wszystkich elementów w tablicy ([@]
), każdy z osobna cytowany.Z opóźnieniem zdaję sobie sprawę, że powinna być w stanie to zrobić. Coś jak:
źródło
INPUTPATH='te*/my files/more
iSEARCH=(${INPUTPATH})
. Bez względu na to, jak zmieniam sposób, w jaki to robię, nadal mam wynik niefunkcjonalny. To wydaje się niemożliwe!find
„s-path
filtr? Używa symboli wieloznacznych i zdecydowanie nie wymaga rozszerzenia.-path
. Jednak w ciągu ostatnich 10 minut wymyśliłem odpowiedź: użyjeval
! Wydaje się to prostsze niż-path
.W końcu znalazłem odpowiedź.
Dodaj ukośnik do wszystkich spacji:
W tym momencie
SEARCH
zawierate*/my\ files/more
.Następnie użyj
eval
.To takie proste! Użycie
eval
pomija interpretację${SEARCH}
pochodzącą ze zmiennej.źródło