Я относительно новичок в Bash и пытаюсь сделать что-то, что на первый взгляд кажется довольно простым - запустите find по иерархии каталогов, чтобы получить все файлы * .wma, канал, который выводит команду, где я конвертирую их в mp3 и сохраните преобразованный файл как .mp3. Я думал, что команда должна выглядеть следующим образом (я перестал использовать команду преобразования звука и вместо этого использую echo для иллюстрации):
$ find ./ -name '*.wma' -type f -print0 | xargs -0 -I f echo ${f%.*}.mp3
Насколько я понимаю, аргумент -print0 позволит мне обрабатывать имена файлов с пробелами (что многие из них делают, поскольку они являются музыкальными файлами). Затем я ожидаю (в результате xargs), что каждый путь к файлу из find будет записан в f, и что с использованием совпадения / удаления подстроки в конце строки, что я должен повторить исходный путь к файлу с mp3 расширение вместо WMA. Однако вместо этого результата я вижу следующее:
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
*.mp3
...
Таким образом, мой вопрос (помимо конкретного «что я здесь делаю неправильно») заключается в следующем: нужно ли обрабатывать значения, являющиеся результатом операции конвейера, в операциях манипуляции со строками иначе, чем значения, которые являются результатом присваивания переменной ?
xargs
сfind
. Он поставляется с-exec
опцией. Вы можете просто добавить команду, которую собираетесь использовать, к своему вопросу, и кто-то может показать вам правильнуюfind
команду?{}
члена)xargs
это более подходит, чемexec
. См. Этот столбец стека stackoverflow.com/questions/896808/find-exec-cmd-vs-xargs для конкретного случая.Ответы:
Как уже определены другие ответы,
${f%.*}
расширяется оболочкой, прежде чем она запускаетxargs
команду. Это расширение необходимо выполнить один раз для каждого имени файла с переменной оболочки, для которойf
задано имя файла (передача-I f
не делает этого:xargs
не имеет понятия о переменной оболочки, она ищет строкуf
в команде, так что если вы используется, например,xargs -I e echo …
он будет выполнять команды, такие как./somedir/somefile.wmacho .mp3
).Продолжая этот подход, скажите,
xargs
чтобы вызвать оболочку, которая может выполнить расширение. Лучше сказать,find
-xargs
это в значительной степени устаревший инструмент, и его трудно использовать правильно, поскольку современные версии find имеют конструкцию, которая выполняет ту же работу (и более) с меньшим количеством трудностей. Вместо тогоfind … -print0 | xargs -0 command …
, чтобы бежатьfind … -exec command … {} +
.Аргумент
_
находится$0
в оболочке; имена файлов передаются как позиционные аргументы, которыеfor f; do …
зацикливаются. Более простая версия этой команды выполняет отдельную оболочку для каждого файла, что эквивалентно, но немного медленнее:Вам на самом деле не нужно использовать
find
здесь, если вы используете достаточно новую оболочку (ksh93, bash ≥4.0 или zsh). В bash, вставьтеshopt -s globstar
ваш,.bashrc
чтобы активировать**/
шаблон glob для повторения в подкаталогах (в ksh, этоset -o globstar
). Тогда вы можете запустить(Если у вас есть вызванные каталоги
*.wma
, добавьте[ -f "$f" ] || continue
в начале цикла.)источник
В случае вашего решения оценка $ {f%. *}. Mp3 выполняется в оболочке, в которую вы вызываете всю команду, а не в оболочке, разветвленной xargs . И в вашей оболочке нет переменной f , она заменяется пустой строкой.
Решение с использованием xargs с -I f :
Но я бы сделал это так:
источник