Пакетное переименование файлов с помощью Bash
как Bash может переименовать ряд пакетов, чтобы удалить их номера версий? Я играл вокруг с обоими expr и %%, но безрезультатно.
примеры:
Xft2-2.1.13.pkg становится Xft2.pkg
jasper-1.900.1.pkg становится jasper.pkg
xorg-libXrandr-1.2.3.pkg становится xorg-libXrandr.pkg
10 ответов:
вы можете использовать функцию расширения параметров bash
for i in ./*.pkg ; do mv "$i" "${i/-[0-9.]*.pkg/.pkg}" ; doneкавычки необходимы для имен файлов с пробелами.
если все файлы находятся в одном каталоге последовательность
ls | sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "" ".pkg"/p' | shбудет делать свою работу. Элемент sed команда создаст последовательность mv команды, которые затем можно передать в оболочку. Лучше всего сначала запустить конвейер без трейлинга
| shчтобы проверить, что команда делает то, что вы хотите.для рекурсии через несколько каталогов используйте что-то вроде
find . -type f | sed -n 's/\(.*\)\(-[0-9.]*\.pkg\)/mv "" ".pkg"/p' | shобратите внимание, что в sed последовательность группирования регулярных выражений состоит из скобок, которым предшествует обратная косая черта,
\(и\), а не отдельные скобки(и).
Я сделаю что-то вроде этого:
for file in *.pkg ; do mv $file $(echo $file | rev | cut -f2- -d- | rev).pkg doneпредполагается, что все ваши файлы находятся в текущем каталоге. Если нет, попробуйте использовать find, как советовал выше Хавьер.
EDIT: кроме того, эта версия не использует никаких специфических функций bash, как и другие выше, что приводит к большей переносимости.
лучше использовать
sedдля этого, что-то вроде:find . -type f -name "*.pkg" | sed -e 's/((.*)-[0-9.]*\.pkg)/ .pkg/g' | while read nameA nameB; do mv $nameA $nameB; doneвычисление регулярного выражения остается в качестве упражнения (как и при работе с именами файлов, которые включают пробелы)
вот POSIX почти эквивалент в настоящее время принимаются ответ. Это торгует только Баш
${variable/substring/replacement}расширение параметра для того, который доступен в любой Bourne-совместимой оболочке.for i in ./*.pkg; do mv "$i" "${i%-[0-9.]*.pkg}.pkg" doneрасширение параметра
${variable%pattern}производит стоимостьюvariableС любым суффиксом, который соответствуетpatternудалены. (Есть еще${variable#pattern}для удаления префикса.)Я сохранил шаблон
-[0-9.]*из принятого ответа, хотя это возможно вводящий в заблуждение. Это не регулярное выражение, а шаблон глобуса; поэтому это не означает "тире, за которым следует ноль или больше чисел или точек". Вместо этого он означает "тире, за которым следует число или точка, а затем что-либо". "Что угодно" будет самым коротким, а не самым длинным матчем. (Баш предлагает##и%%для обрезки максимально длинного префикса или суффикса, а не самого короткого.)
Это, кажется, работает, предполагая, что
- все заканчивается $pkg
- ваша версия #всегда начинается с" -"
сдирать .pkg, затем раздеться -..
for x in $(ls); do echo $x $(echo $x | sed 's/\.pkg//g' | sed 's/-.*//g').pkg; done
у меня было несколько
*.txtфайлы будут переименованы как.sqlв той же папке. ниже работало для меня:for i in \`ls *.txt | awk -F "." '{print }'\` ;do mv $i.txt $i.sql; done
можно предположить
sedдоступно на любом *nix, но мы не можем быть уверены он будет поддерживатьsed -nдля генерации команд mv. (Примечание: только GNUsedэто.)даже так, bash builtins и sed, мы можем быстро взбить функцию оболочки, чтобы сделать это.
sedrename() { if [ $# -gt 1 ]; then sed_pattern= shift for file in $(ls $@); do mv -v "$file" "$(sed $sed_pattern <<< $file)" done else echo "usage: sed_pattern files..." fi }использование
sedrename 's|\(.*\)\(-[0-9.]*\.pkg\)||' *.pkg before: ./Xft2-2.1.13.pkg ./jasper-1.900.1.pkg ./xorg-libXrandr-1.2.3.pkg after: ./Xft2.pkg ./jasper.pkg ./xorg-libXrandr.pkgсоздание целевой папки:
С
mvне создает автоматически целевые папки, которые мы не можем использовать наша первоначальная версияsedrename.это довольно небольшое изменение, поэтому было бы неплохо включить эту функцию:
нам понадобится функция полезности,
abspath(или абсолютный путь) с момента bash у него нет этой сборки.abspath () { case "" in /*)printf "%s\n" "";; *)printf "%s\n" "$PWD/";; esac; }как только у нас есть, что мы можем создать целевую папку(ы) для a СЭД/переименовать шаблон, который включает в себя новую структуру папок.
это гарантирует, что мы знаем имена наших целевых папок. Когда мы переименовать нам нужно будет использовать его в целевом файле имя.
# generate the rename target target="$(sed $sed_pattern <<< $file)" # Use absolute path of the rename target to make target folder structure mkdir -p "$(dirname $(abspath $target))" # finally move the file to the target name/folders mv -v "$file" "$target"вот полный скрипт с поддержкой папок...
sedrename() { if [ $# -gt 1 ]; then sed_pattern= shift for file in $(ls $@); do target="$(sed $sed_pattern <<< $file)" mkdir -p "$(dirname $(abspath $target))" mv -v "$file" "$target" done else echo "usage: sed_pattern files..." fi }конечно, он все еще работает, когда у нас нет конкретной целевой папки тоже.
если бы мы хотели поместить все песни в папку,
./Beethoven/мы можем сделать это:использование
sedrename 's|Beethoven - |Beethoven/|g' *.mp3 before: ./Beethoven - Fur Elise.mp3 ./Beethoven - Moonlight Sonata.mp3 ./Beethoven - Ode to Joy.mp3 ./Beethoven - Rage Over the Lost Penny.mp3 after: ./Beethoven/Fur Elise.mp3 ./Beethoven/Moonlight Sonata.mp3 ./Beethoven/Ode to Joy.mp3 ./Beethoven/Rage Over the Lost Penny.mp3бонусный раунд...
используя этот скрипт для перемещения файлов из папок в одну папку:
предположим, что мы хотели собрать все файлы подобраны, и разместите их в текущей папке мы можем это сделать:
sedrename 's|.*/||' **/*.mp3 before: ./Beethoven/Fur Elise.mp3 ./Beethoven/Moonlight Sonata.mp3 ./Beethoven/Ode to Joy.mp3 ./Beethoven/Rage Over the Lost Penny.mp3 after: ./Beethoven/ # (now empty) ./Fur Elise.mp3 ./Moonlight Sonata.mp3 ./Ode to Joy.mp3 ./Rage Over the Lost Penny.mp3обратите внимание на sed regex patterns
обычные правила шаблона sed применяются в этом скрипте, эти шаблоны не являются PCRE (Perl-совместимые регулярные выражения). Вы могли бы sed расширенный синтаксис регулярных выражений, используя либо
sed -rилиsed -Eв зависимости от вашей платформы.смотрите POSIX совместимый
man re_formatдля полного описания sed основное и расширенное регулярное выражение узоры.
Спасибо за ответы. У меня тоже была какая-то проблема. Движущийся.nzb.в очередь файлы .nzb файлов. У него были пробелы и другие cruft в именах файлов, и это решило мою проблему:
find . -type f -name "*.nzb.queued" | sed -ne "s/^\(\(.*\).nzb.queued\)$/mv -v \"\" \".nzb\"/p" | shОн основан на ответе Diomidis Spinellis.
регулярное выражение создает одну группу для всего имени файла и одну группу для предыдущей части.nzb.помещается в очередь, а затем создает команду перемещения оболочки. Со строками в кавычках. Это также позволяет избежать создания цикла в сценарии оболочки, потому что это уже сделано СЭД.
Я считаю, что переименование является гораздо более простым инструментом для использования для такого рода вещей. Я нашел его на Homebrew для OSX
для вашего примера я бы сделал:
rename 's/\d*?\.\d*?\.\d*?//' *.pkg's' означает замену. Форма s/searchPattern/ replacement / files_to_apply. Вам нужно использовать регулярное выражение для этого, которое требует небольшого изучения, но это стоит усилий.
Comments