Najpierw odetnij banalne, ale nie dające się zastosować odpowiedzi: nie mogę użyć ani sztuczki find
+, xargs
ani jej wariantów (podobnie jak w find
przypadku -exec
), ponieważ muszę użyć kilku takich wyrażeń na rozmowę. Wrócę do tego na końcu.
Teraz dla lepszego przykładu zastanówmy się:
$ find -L some/dir -name \*.abc | sort
some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Jak przekazać je jako argumenty program
?
Samo robienie tego nie załatwia sprawy
$ ./program $(find -L some/dir -name \*.abc | sort)
kończy się niepowodzeniem, ponieważ program
otrzymuje następujące argumenty:
[0]: ./program
[1]: some/dir/1.abc
[2]: some/dir/2.abc
[3]: some/dir/a
[4]: space.abc
Jak widać, ścieżka z przestrzenią została podzielona i program
uważa, że to dwa różne argumenty.
Cytuj, aż to zadziała
Wydaje się, że początkujący użytkownicy tacy jak ja, w obliczu takich problemów, mają tendencję do losowego dodawania cudzysłowów, aż w końcu to działa - tylko tutaj nie wydaje się, aby to pomogło…
"$(…)"
$ ./program "$(find -L some/dir -name \*.abc | sort)"
[0]: ./program
[1]: some/dir/1.abc
some/dir/2.abc
some/dir/a space.abc
Ponieważ cudzysłowy uniemożliwiają dzielenie słów, wszystkie pliki są przekazywane jako pojedynczy argument.
Cytując poszczególne ścieżki
Obiecujące podejście:
$ ./program $(find -L some/dir -name \*.abc -printf '"%p"\n' | sort)
[1]: "some/dir/1.abc"
[2]: "some/dir/2.abc"
[3]: "some/dir/a
[4]: space.abc"
Oczywiście są tam cytaty. Ale nie są już interpretowane. Są tylko częścią strun. Więc nie tylko nie zapobiegli podziałowi słów, ale także wdali się w kłótnie!
Zmień IFS
Potem próbowałem się bawić IFS
. Wolałbym find
się -print0
i sort
ze -z
i tak - tak, że będą mieli żadnych problemów na „wired” samych ścieżkach. Dlaczego więc nie wymusić podziału słów na null
postać i mieć to wszystko?
$ ./program $(IFS=$'\0' find -L some/dir -name \*.abc -print0 | sort -z)
[0]: ./program
[1]: some/dir/1.abcsome/dir/2.abcsome/dir/a
[2]: space.abc
Więc nadal dzieli się na przestrzeń i nie dzieli na null
.
Próbowałem umieścić IFS
zadanie zarówno w $(…)
(jak pokazano powyżej), jak i wcześniej ./program
. Próbowałem również inne składni jak \0
, \x0
, \x00
zarówno cytowana '
i "
jak również i bez $
. Żadne z nich nie miało znaczenia…
I tutaj brakuje mi pomysłów. Próbowałem jeszcze kilku rzeczy, ale wszystkie wydawały się sprowadzać do tych samych problemów, co wymienione.
Co jeszcze mogłem zrobić? Czy to w ogóle wykonalne?
Jasne, mógłbym program
zaakceptować wzorce i sam przeszukać. Ale jest to dużo podwójnej pracy przy ustalaniu określonej składni. (A co grep
na przykład z udostępnianiem plików ?).
Mógłbym również program
zaakceptować plik z listą ścieżek. Następnie mogę łatwo zrzucić find
wyrażenie do pliku tymczasowego i podać ścieżkę tylko do tego pliku. Może to być obsługiwane wzdłuż bezpośrednich ścieżek, dzięki czemu jeśli użytkownik ma tylko prostą ścieżkę, można ją podać bez pośredniego pliku. Ale to nie wydaje się miłe - trzeba stworzyć dodatkowe pliki i się nimi zająć, nie wspominając o dodatkowej implementacji. (Na plus można jednak ratować przypadki, w których liczba plików jako argumentów zaczyna powodować problemy z długością wiersza poleceń…)
Na koniec jeszcze raz przypomnę, że sztuczki find
+ xargs
(i podobne) nie będą działać w moim przypadku. Dla uproszczenia opisu pokazuję tylko jeden argument. Ale mój prawdziwy przypadek wygląda mniej więcej tak:
$ ABC_FILES=$(find -L some/dir -name \*.abc | sort)
$ XYZ_FILES=$(find -L other/dir -name \*.xyz | sort)
$ ./program --abc-files $ABC_FILES --xyz-files $XYZ_FILES
Więc wykonanie xargs
jednego wyszukiwania wciąż pozostawia mi sposób radzenia sobie z drugim…
mapfile
(ani jego synonimiereadarray
). Ale to działa!