
Я хочу использовать find для поиска определенных файлов, а затем использовать xargs с cp и sed для перемещения этих файлов в другую папку и переименования их. Я знаю, как сделать это в цикле, но это не то, что я ищу.
Я пытался:
find ${FOLDER} -iname "*${SOME_STRING}*" | xargs -I {} cp {} $(echo {} | sed 's/ABC/XYZ/g')
Почему это не работает и какое может быть решение?
решение1
Попробуйте это. Это не нужно xargs
, просто find
, sed
и copy
. Это не изменит никаких файлов, новолявывести список команд оболочки для копирования файлов. Так что если вам нравятся команды, которые она печатает, то вы запускаете ее снова и удаляете перед #
в sh -x
последней строке и позволяете оболочке выполнять команды.
find "${FOLDER:-.}" -iname "*${SOME_STRING:-ABC}*" |
sed "
s/^/'/ # surround filename with single quotes
s/$/'/
h # save filename in the sed hold space
s/ABC/XYZ/g # change filename
H # append to hold space (separates with newline)
g # get original and modified from hold
s/\n/ /g # replace the newline with a space
s/^/cp -i/ # make it into a copy command
" #| sh -x # optionally pipe to shell
Почему этот подход лучше, чем xargs
в этом случае? Потому что этот метод запускает всего 3 процесса ( find
, sed
, и sh
) в дополнение к требуемой cp
команде для каждого файла.
Для использования xargs
обработки каждого имени файла потребуется больше процессов, чем требуется для одной cp
команды.
Гораздо эффективнее позволить одному вызову sed сгенерироватьвсекоманд cp
, чем вызывать новый sed
процесс для каждого имени файла.
решение2
С использованием GNU Parallel это выглядит так:
find ${FOLDER} -iname "*${SOME_STRING}*" |
parallel cp {} '{= s/ABC/XYZ/g =}'
Конструкция {= =} содержит выражение Perl, которое изменяет $_.
Одним из преимуществ является то, что GNU Parallel делает правильные вещи, даже если у вас есть файлы с именами:
My brother's 12" records worth >100$.txt
или ужасы вроде:
touch Y-"$(perl -e 'print pack("c*",1..9,11..46,48..255)')"