Пакетное переименование файлов с помощью 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

737   10  

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. (Примечание: только GNU sed это.)

даже так, 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

    Ничего не найдено.