3

Вдохновлен этим вопросом. Оригинальный вопрос, в общем, «Как превратить :2f в - во всех файлов в папке». Например, если у меня есть файл ./abc:2fdef он должен быть переименован в ./abc-def .

Сначала я думал, что это простая задача ... find все файлы, а затем sed заменить :2f в - . При попытке построить однострочник, я прихожу с командой:

find . -type f -name '*:2f*' | xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")

Однако это не работает. Проведя много тестов, я обнаружил, что проблема заключается в части xargs - $() был выполнен до того, как xargs поместит вместо {} имена файлов. Разрабатывать,

xargs -I {} mv {} $(echo {} | sed "s/:2f/-/ig")

был оценен как ($(...) был оценен)

xargs -I {} mv {} {}

а потом

mv ./abc:2fdef ./abc:2fdef

Что было не то, что я ожидаю. Итак, мой вопрос: могу ли я сделать так, чтобы xargs подставлял все {} в имена файлов перед вычислением части $(...) ?

1 ответ1

5

Нет, потому что xargs не может заменить что-либо до того, как оболочка xargs с уже оцененным $(…) . Это связано с порядком расширения оболочки .

Я бы, наверное, сделал это так:

find . -type f -name '*:2f*' -exec bash -c 'mv -- "$0" "${0//:2f/-}"' {} \;

Здесь вызов оболочки вычисляется из каждого файла, найденного функцией find , и замена строки выполняется с помощью функций оболочки, а не другого вызова sed .

Кроме того, этот подход более безопасен, потому что пробелы в именах файлов обрабатываются правильно (через двойные кавычки аргументов для вызова mv ). Подробнее об этом здесь.


Для этих задач вам, вероятно, понадобится более эффективный инструмент, такой как zmv, который доступен в Zsh, или rename Perl, которое поставляется со многими дистрибутивами Linux:

rename 's/:2f/-/' *

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .