3

У меня есть около 15 лотов из более 100 каталогов, в частности, используя псевдокод, как вы можете:

rename * *suffix  
rename * prefix*  
rename * CAPITALIZE*  

НО советы или ссылки на учебники, относящиеся к работе с несколькими файлами и каталогами, будут оценены.

6 ответов6

5

Многие системы Linux / Unix поставляются с perl-скриптом rename или rename.pl или prename который позволяет переименовывать через выражения perl. В системах Debian он устанавливается вместе с пакетом perl .

$ rename
Usage: rename [-v] [-n] [-f] perlexpr [filenames]

Магия происходит в аргументе perlexpr . По сути, это небольшой кусочек Perl-кода, который будет работать с каждым именем файла. Вам не нужно предоставлять никаких циклов, просто напишите код, который преобразует ваш ввод в желаемый вывод. (Обязательно и в кавычках выражение; я использую одинарные кавычки для защиты от расширения оболочки, если это не является абсолютно необходимым.)

Итак, для ваших примеров:

  • переименовать * * суффикс

    $ rename 's/$/suffix/' *
              ^ ^  ^^^^
              | |    +-- your suffix goes here
              | +------- indicates end-of-string
              +--------- perl's substitution operator (s/from-regex/to/)
    
  • переименовать * префикс *

    $ rename 's/^/prefix/' *
                ^  ^^^^
                |    +-- your prefix goes here
                +------- indicates beginning-of-string
    
  • переименовать * CAPITALIZE *

    $ rename '$_ = uc' *
              ^^^^ ^^
               |    +-- perl builtin function to capitalize a string
               +------- replaces input filename
    

Смотрите другие примеры из книги O'Reilly Unix Power Tools .

2

Это будет работать для добавления префиксов и суффиксов ко всем именам файлов.

find /base/dir/path -type f -exec mv {} prefix{}suffix \;
#                                    -- ^^^^^^--^^^^^^

Для заглавных букв вы могли бы написать короткий цикл bash который будет использовать что-то вроде sed чтобы изменить регистр букв, а затем переместить.

Я предлагаю прочитать,

  1. Усовершенствованный сценарий Bash
  2. Perl скриптинг
2

Я бы использовал Perl - и, в частности, эту модифицированную версию сценария «переименования», которая была в 1-м издании книги «Верблюд» (но выпала из второго и третьего изданий из-за недостатка места).

Использование:

find . -type f -print0 | xargs -0 rename 's%/([^/]+)$%/prefix\U${1}\Esuffix%'

Что в переводе означает:

  • найдите все файлы, даже те, в имени которых есть пробелы, и обработайте их правильно.
  • для каждого имени файла найдите имя после последней косой черты, помня его как «$ {1}»
  • замените имя на «префикс», заглавную версию в верхнем регистре и «суффикс»

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


#!/Users/jleffler/perl/v5.10.0/bin/perl -w
#
# @(#)$Id: rename.pl,v 1.7 2008/02/16 07:53:08 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command

use strict;
use Getopt::Std;

my(%opts);
my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;

die $usage unless getopts('fnxV', \%opts);

if ($opts{V})
{
    printf "%s\n", q'RENAME Version $Revision: 1.7 $ ($Date: 2008/02/16 07:53:08 $)';
    exit 0;
}
$force = 1 if ($opts{f});
$noexc = 1 if ($opts{n});
$trace = 1 if ($opts{x});

my($op) = shift;
die $usage unless defined $op;

if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}

for (@ARGV)
{
    if (-e $_ || -l $_)
    {
        my($was) = $_;
        eval $op;
        die $@ if $@;
        next if ($was eq $_);
        if ($force == 0 && -f $_)
        {
            print STDERR "rename failed: $was - $_ exists\n";
        }
        else
        {
            print "+ $was --> $_\n" if $trace;
            print STDERR "rename failed: $was - $!\n"
                unless ($noexc || rename($was, $_));
        }
    }
    else
    {
        print STDERR "$_ - $!\n";
    }
}

Для чего бы это ни стоило, я столкнулся с постоянной ошибкой, которая не была ужасно информативной, когда я пытался:

$ find . -type f -print0 | xargs -0 rename 's/.*/prefix$&suffix/'
rename failed: ./xxx-32 - No such file or directory
rename failed: ./xxx-64 - No such file or directory
rename failed: ./xxx.c - No such file or directory
rename failed: ./xxx.c~ - No such file or directory
$

Это было странно - я вижу эти файлы ...

Использование опции «-x» для «переименования» показало мне, в чем проблема:

rename failed: ./xxx-32 - No such file or directory
rename failed: ./xxx-64 - No such file or directory
rename failed: ./xxx.c - No such file or directory
rename failed: ./xxx.c~ - No such file or directory
+ ./xxx-32 --> prefix./xxx-32suffix
+ ./xxx-64 --> prefix./xxx-64suffix
+ ./xxx.c --> prefix./xxx.csuffix
+ ./xxx.c~ --> prefix./xxx.c~suffix

Ах да, нет подкаталога с префиксом. в моем текущем каталоге!

1

Для заглавных букв в нижнем регистре, как насчет:

for filename in *                # Traverse all files in directory.
do
   fname=`basename $filename`
   n=`echo $fname | tr A-Z a-z`  # Change name to lowercase.
   if [ "$fname" != "$n" ]       # Rename only files not already lowercase.
   then
     mv $fname $n
   fi  
done   

Похищен бесстыдно из Проекта документации Linux: http://tldp.org/LDP/abs/html/textproc.html

Должно быть проще (и меньше ресурсов), чем использование Perl.

0

Мне нравится Perl, лучше rename , если он у тебя есть или ты можешь его получить.

Вот несколько вариантов UPPERCASE:

# take out the echo to make these do the work

# find + xargs + bash (v4) + mv
# requires bash 4 for the ^^ uppercasing feature
find * -type f -print0 | xargs -0 bash -c 'for f in "$@"; do dir="";case "$1" in (*/*) dir="${f%/*}/";;esac;filename="${f##*/}"; echo mv "$f" "$dir${filename^^}"; done' mv

# find + xargs + sh + dirname + basename + tr + mv
# maybe easier to understand than above, but noticeably slower due to 3 forks per file
find * -type f -print0 | xargs -0 sh -c 'for f in "$@"; do echo mv "$f" "$(dirname "$f")/$(printf "$(basename "$f")" | tr "[:lower:]" "[:upper:]")"; done' mv

В последнее время я играл с zsh , так что вызовы zmv :

# If the command line shell is not zsh, the prefix each of these commands with
#    zsh -fc 'autoload -U zmv && zmv $@'
# take the -n off to make it do the work instead of just talk about it

zmv -Qn '(**/)(*)(.)' '${1}prefix${2}'
zmv -Qn '(**/)(*)(.)' '${1}${2}suffix'
zmv -Qn '(**/)(*)(.)' '${1}${(U)2}'
# without the (.) qualifier (and the enabling -Q), dirs are processed also
zmv -n '(**/)(*)' '${1}prefix${2}'
zmv -n '(**/)(*)' '${1}${2}suffix'
zmv -n '(**/)(*)' '${1}${(U)2}'
0

Этот сценарий переименования perl оценивает первый аргумент как код для переименования файлов, заданных с остальными аргументами.

#!/usr/bin/perl

($op = shift) || die "Usage: $0 perlexpr [filenames]\n";
if (!@ARGV) {
    @ARGV = <STDIN>;
    chop(@ARGV);
}
for (@ARGV) {
    $was = $_;
    eval $op;
    die $@ if $@;
    rename($was,$_) unless $was eq $_;
}

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