Jestem stosunkowo nowy w Bash i próbuję zrobić coś, co na pozór wydawało się dość proste - uruchom wyszukiwanie w hierarchii katalogów, aby uzyskać wszystkie pliki * .wma, potokuj dane wyjściowe do polecenia, w którym przekonwertuję je na mp3 i zapisz przekonwertowany plik jako .mp3. Myślałem, że polecenie powinno wyglądać następująco (zrezygnowałem z polecenia konwersji audio i zamiast tego używam echa do ilustracji):
$ find ./ -name '*.wma' -type f -print0 | xargs -0 -I f echo ${f%.*}.mp3
Jak rozumiem, argument -print0 pozwoli mi obsługiwać nazwy plików ze spacjami (co wiele z nich robi, ponieważ są plikami muzycznymi). Spodziewam się (w wyniku xargs), że każda ścieżka pliku znalezienia jest przechwytywana wf, i że używając podłańcucha dopasuj / usuń z końca łańcucha, powinienem powtórzyć oryginalną ścieżkę pliku z mp3 rozszerzenie zamiast wma. Jednak zamiast tego wyniku widzę:
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
...
Tak więc moje pytanie (oprócz konkretnego „co tutaj robię źle”) brzmi: czy wartości, które są wynikiem operacji potoku, muszą być traktowane inaczej w operacjach manipulacji ciągiem niż te, które są wynikiem przypisania zmiennej ?
xargs
zfind
. Pochodzi z-exec
opcją. Czy możesz po prostu dodać do pytania polecenie, którego zamierzasz użyć, a ktoś może pokazać prawidłowefind
polecenie?{}
członka)xargs
jest bardziej odpowiednie niżexec
. Zobacz przykład stosu stackoverflow.com/questions/896808/find-exec-cmd-vs-xargs dla konkretnego przypadku.Odpowiedzi:
Jak już zidentyfikowano inne odpowiedzi,
${f%.*}
jest on rozszerzany przez powłokę przed uruchomieniemxargs
polecenia. Potrzebujesz tego rozszerzenia, aby miało miejsce raz dla każdej nazwy pliku, ze zmienną powłokif
ustawioną na nazwę pliku (przekazanie-I f
tego nie robi:xargs
nie ma pojęcia zmiennej powłoki, szuka ciąguf
w poleceniu, więc jeśli używane npxargs -I e echo …
. wykonywałby polecenia takie jak./somedir/somefile.wmacho .mp3
).Kontynuując to podejście, powiedz,
xargs
aby wywołać powłokę, która może wykonać rozszerzenie. Lepiej, powiedzfind
-xargs
jest w dużej mierze przestarzałym narzędziem i jest trudne w użyciu, ponieważ nowoczesne wersje find mają konstrukcję, która wykonuje tę samą pracę (i więcej) z mniejszymi trudnościami hydraulicznymi. Zamiastfind … -print0 | xargs -0 command …
biegaćfind … -exec command … {} +
.Argument
_
znajduje się$0
w powłoce; nazwy plików są przekazywane jako argumenty pozycyjne, którefor f; do …
zapętlają się. Prostsza wersja tego polecenia wykonuje osobną powłokę dla każdego pliku, co jest równoważne, ale nieco wolniejsze:Tak naprawdę nie musisz go
find
tutaj używać , zakładając, że używasz stosunkowo nowej powłoki (ksh93, bash ≥4,0 lub zsh). W bash, umieścićshopt -s globstar
w twojej.bashrc
aby aktywować**/
wzorzec glob rekursja w podkatalogów (w ksh, to jestset -o globstar
). Potem możesz biec(Jeśli masz wywołane katalogi
*.wma
, dodaj[ -f "$f" ] || continue
na początku pętli).źródło
W przypadku oceny rozwiązania $ {f%. *}. Mp3 odbywa się w powłoce, w której wywołujesz całe polecenie, a nie w powłoce rozwidlonej przez xargs . A w twojej powłoce nie ma zmiennej f , jest ona zastąpiona pustym łańcuchem.
Rozwiązanie wykorzystujące xargs z -I f :
Ale zrobiłbym to w ten sposób:
źródło