BASH:处理多个文件和目录

BASH:处理多个文件和目录

我有大约 15 个 100 多个目录,具体使用伪代码你如何:

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

但如果能提供有关处理多个文件和目录的具体提示或教程链接,我们将不胜感激。

答案1

许多 linux/unix 系统都带有rename或perl 脚本rename.plprename允许通过 perl 表达式重命名。在 Debian 系统上,它与软件包一起安装perl

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

魔法发生在perlexpr参数中。这本质上是一小段 perl 代码,将对每个文件名进行操作。您不需要提供任何循环,只需编写将输入转换为所需输出的代码即可。(请务必引用表达式;除非绝对必要,否则我使用单引号来防止 shell 扩展。)

因此,对于你的例子:

  • 重命名 * *后缀

    $ 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
    

查看 O'Reilly 的更多示例Unix 电动工具书。

答案2

这适用于所有文件名的前缀和后缀添加。

查找 /base/dir/path -type f -exec mv {} 前缀{}后缀 \;
# -- ^^^^^^--^^^^^^

对于大写字母,您可能要编写一个短bash循环,使用类似的东西sed来改变字母大小写,然后移动。

我建议阅读,

  1. 高级 Bash 脚本指南
  2. Perl脚本

答案3

我会使用 Perl - 特别是 Camel 书第 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

哦,对了——我当前的目录中没有名为“前缀”的子目录!

答案4

rename如果你有或者可以得到 Perl,我最喜欢它。

以下是一些大写字母的变体:

# 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}'

相关内容