Bash: Работа с несколькими файлами и каталогами

У меня есть приблизительно 15 партий 100 + каталоги, конкретно с помощью псевдокода, как может Вы:

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

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

3
задан 31.10.2009, 11:26

5 ответов

Много систем linux/unix идут с a rename или rename.pl или prename perl-сценарий, который позволяет переименовывать через выражения жемчуга. В системах Debian это установлено с perl пакет.

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

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

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

  • переименуйте * * суффикс

    $ 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
    
  • переименуйте *, ИСПОЛЬЗУЮТ ДЛЯ СВОЕЙ ВЫГОДЫ*

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

Посмотрите больше примеров из книги Электроинструментов Unix O'Reilly.

5
ответ дан 07.12.2019, 23:04
  • 1
    Но с осторожностью это может все быть сделано в одной операции! уверенный – Jonathan Leffler 31.10.2009, 06:57
  • 2
    ! я принимаю три различных примера, не три операции в единственном примере. – quack quixote 31.10.2009, 07:11

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

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

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

Я предложу читать,

  1. Усовершенствованная хитрость сценариев Bash
  2. Perl сценарии
2
ответ дан 07.12.2019, 23:04

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

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

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

О, право - нет подкаталога, названного 'префиксом'. в моем текущем каталоге!

2
ответ дан 07.12.2019, 23:04
  • 1
    +1 для find -print0 | xargs -0 – Chris Johnsen 31.10.2009, 11:35
  • 2
    @Jonathan Leffler: Я чувствую, что Вы и благословили и замучили меня, поскольку Ваш сценарий является удачей... все же я чувствую, что должен выучить другой язык, а именно, Perl, сразу.:) Спасибо, очень. – Ande TURNER 31.10.2009, 16:25

Для ограничений к нижнему регистру, как насчет:

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.

1
ответ дан 07.12.2019, 23:04
  • 1
    Это не изменит имена файлов, просто верхний регистр содержание файлов (и дамп это к stdout). – Chris Johnsen 31.10.2009, 11:36

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

Вот некоторые ПРОПИСНЫЕ изменения:

# 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
ответ дан 07.12.2019, 23:04

Теги

Похожие вопросы