![BASH:处理多个文件和目录](https://linux22.com/image/1220484/BASH%EF%BC%9A%E5%A4%84%E7%90%86%E5%A4%9A%E4%B8%AA%E6%96%87%E4%BB%B6%E5%92%8C%E7%9B%AE%E5%BD%95.png)
我有大约 15 个 100 多个目录,具体使用伪代码你如何:
rename * *suffix
rename * prefix*
rename * CAPITALIZE*
但如果能提供有关处理多个文件和目录的具体提示或教程链接,我们将不胜感激。
答案1
许多 linux/unix 系统都带有rename
或perl 脚本rename.pl
,prename
允许通过 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
来改变字母大小写,然后移动。
我建议阅读,
答案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}'