在一个目录中有多个以fgh开头的文件,例如:
fghfilea
fghfileb
fghfilec
我想将它们全部重命名为以前缀jkl开头。是否有一个单独的命令来执行该操作,而不是逐个重命名每个文件?
在一个目录中有多个以fgh开头的文件,例如:
fghfilea
fghfileb
fghfilec
我想将它们全部重命名为以前缀jkl开头。是否有一个单独的命令来执行该操作,而不是逐个重命名每个文件?
当前回答
我建议使用我自己的脚本,它可以解决这个问题。它还有更改文件名编码的选项,以及将组合符号转换为预组合字符的选项,这是我从Mac上复制文件时经常遇到的问题。
#!/usr/bin/perl
# Copyright (c) 2014 André von Kugland
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
$help_msg =
"rename.pl, a script to rename files in batches, using Perl
expressions to transform their names.
Usage:
rename.pl [options] FILE1 [FILE2 ...]
Where options can be:
-v Verbose.
-vv Very verbose.
--apply Really apply modifications.
-e PERLCODE Execute PERLCODE. (e.g. 's/a/b/g')
--from-charset=CS Source charset. (e.g. \"iso-8859-1\")
--to-charset=CS Destination charset. (e.g. \"utf-8\")
--unicode-normalize=NF Unicode normalization form. (e.g. \"KD\")
--basename Modifies only the last element of the path.
";
use Encode;
use Getopt::Long;
use Unicode::Normalize 'normalize';
use File::Basename;
use I18N::Langinfo qw(langinfo CODESET);
Getopt::Long::Configure ("bundling");
# ----------------------------------------------------------------------------------------------- #
# Our variables. #
# ----------------------------------------------------------------------------------------------- #
my $apply = 0;
my $verbose = 0;
my $help = 0;
my $debug = 0;
my $basename = 0;
my $unicode_normalize = "";
my @scripts;
my $from_charset = "";
my $to_charset = "";
my $codeset = "";
# ----------------------------------------------------------------------------------------------- #
# Get cmdline options. #
# ----------------------------------------------------------------------------------------------- #
$result = GetOptions ("apply" => \$apply,
"verbose|v+" => \$verbose,
"execute|e=s" => \@scripts,
"from-charset=s" => \$from_charset,
"to-charset=s" => \$to_charset,
"unicode-normalize=s" => \$unicode_normalize,
"basename" => \$basename,
"help|h|?" => \$help,
"debug" => \$debug);
# If not going to apply, then be verbose.
if (!$apply && $verbose == 0) {
$verbose = 1;
}
if ((($#scripts == -1)
&& (($from_charset eq "") || ($to_charset eq ""))
&& $unicode_normalize eq "")
|| ($#ARGV == -1) || ($help)) {
print $help_msg;
exit(0);
}
if (($to_charset ne "" && $from_charset eq "")
||($from_charset eq "" && $to_charset ne "")
||($to_charset eq "" && $from_charset eq "" && $unicode_normalize ne "")) {
$codeset = langinfo(CODESET);
$to_charset = $codeset if $from_charset ne "" && $to_charset eq "";
$from_charset = $codeset if $from_charset eq "" && $to_charset ne "";
}
# ----------------------------------------------------------------------------------------------- #
# Composes the filter function using the @scripts array and possibly other options. #
# ----------------------------------------------------------------------------------------------- #
$f = "sub filterfunc() {\n my \$s = shift;\n";
$f .= " my \$d = dirname(\$s);\n my \$s = basename(\$s);\n" if ($basename != 0);
$f .= " for (\$s) {\n";
$f .= " $_;\n" foreach (@scripts); # Get scripts from '-e' opt. #
# Handle charset translation and normalization.
if (($from_charset ne "") && ($to_charset ne "")) {
if ($unicode_normalize eq "") {
$f .= " \$_ = encode(\"$to_charset\", decode(\"$from_charset\", \$_));\n";
} else {
$f .= " \$_ = encode(\"$to_charset\", normalize(\"$unicode_normalize\", decode(\"$from_charset\", \$_)));\n"
}
} elsif (($from_charset ne "") || ($to_charset ne "")) {
die "You can't use `from-charset' nor `to-charset' alone";
} elsif ($unicode_normalize ne "") {
$f .= " \$_ = encode(\"$codeset\", normalize(\"$unicode_normalize\", decode(\"$codeset\", \$_)));\n"
}
$f .= " }\n";
$f .= " \$s = \$d . '/' . \$s;\n" if ($basename != 0);
$f .= " return \$s;\n}\n";
print "Generated function:\n\n$f" if ($debug);
# ----------------------------------------------------------------------------------------------- #
# Evaluates the filter function body, so to define it in our scope. #
# ----------------------------------------------------------------------------------------------- #
eval $f;
# ----------------------------------------------------------------------------------------------- #
# Main loop, which passes names through filters and renames files. #
# ----------------------------------------------------------------------------------------------- #
foreach (@ARGV) {
$old_name = $_;
$new_name = filterfunc($_);
if ($old_name ne $new_name) {
if (!$apply or (rename $old_name, $new_name)) {
print "`$old_name' => `$new_name'\n" if ($verbose);
} else {
print "Cannot rename `$old_name' to `$new_name'.\n";
}
} else {
print "`$old_name' unchanged.\n" if ($verbose > 1);
}
}
其他回答
我编写了这个脚本来搜索所有.mkv文件,递归地将找到的文件重命名为.avi。您可以根据自己的需要定制它。我还添加了一些其他的东西,比如从文件路径中获取文件目录,扩展名,文件名,以防你将来需要引用一些东西。
find . -type f -name "*.mkv" | while read fp; do
fd=$(dirname "${fp}");
fn=$(basename "${fp}");
ext="${fn##*.}";
f="${fn%.*}";
new_fp="${fd}/${f}.avi"
mv -v "$fp" "$new_fp"
done;
这里有一个使用命令行Groovy的方法:
groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}'
这是find + sed + xargs解决方案的扩展版本。
原来的解是这个和这个。
要求:搜索,修剪,正则表达式,重命名
我想重命名多个文件夹中的多个文件。 一些文件夹应该被删除。 我在cygwin上,不能让perl重命名工作,这是最流行的解决方案所需要的(我假设它很慢,因为它似乎没有修剪选项?)
解决方案
使用find可以有效地获取文件(带有修剪),并提供许多自定义选项。 使用sed替换正则表达式。 使用xargs将结果汇集到最终命令中。
例1:重命名*.js文件,忽略node_modules
这个示例查找文件并对找到的文件和重命名的文件进行回显。出于安全考虑,它目前没有移动任何东西。你需要用mv代替echo。
set -x # stop on error
set -e # verbose mode (echo all commands)
find "." -type f -not \( -path "**/node_modules/**" -prune \) -name "*.js" |
sed -nE "s/(.*)\/my(.*)/& \1\/YOUR\2/p" |
xargs -n 2 echo # echo first (replace with `mv` later)
上面的脚本转换为:
./x/y/my-abc.js
到这个:
./x/y/YOUR-abc.js
溶液分解
find "." -type f -not \( -path "**/node_modules/**" -prune \) -name "*.js" Searches for files (-type f). The -not part excludes (and, importantly does not traverse!) the (notoriously ginormous) node_modules folder. File name must match "*.js". You can add more include and exclude clauses. Refs: This post discusses recursive file finding alternatives. This post discusses aspects of pruning and excluding. man find sed -nE "s/(.*)\/my\-(.*\.js)/& \1\/YOUR-\2/p" NOTE: sed always takes some getting used to. -E enables "extended" (i.e. more modern) regex syntax. -n is used in combination with the trailing /p flag: -n hides all results, while /p will print only matching results. This way, we only see/move files that need changing, and ignore all others. Replacement regex with sed (and other regex tools) is always of the format: s/regex/replacement/FLAGS In replacement, the & represents the matched input string. This will be the first argument to mv. Refs: linux regex tutorial man sed xargs -n 2 echo Run the command echo with (the first two strings of) the replaced string. Refs: man xargs
好运!
有几种方法,但使用rename可能是最简单的。
使用一个版本的rename (Perl的rename):
rename 's/^fgh/jkl/' fgh*
使用另一个版本的rename(与Judy2K的答案相同):
rename fgh jkl fgh*
您应该检查您的平台的手册页,以确定上述哪一种方法适用。
使用StringSolver工具(windows & Linux bash),通过示例处理:
filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea
它首先根据示例计算一个过滤器,其中输入是文件名和输出(ok和notok,任意字符串)。如果filter有选项——auto或者在这个命令之后单独被调用,它会创建一个文件夹ok和一个文件夹notok,并分别将文件推送到它们。
然后使用过滤器,mv命令是一个半自动的移动,使用修饰符——auto变成自动的。使用前面的过滤器——filter,它找到了从fghfilea到jklfilea的映射,然后将其应用于所有过滤过的文件。
其他单行解决方案
做同样事情的其他等效方法(每一行都是等效的),所以你可以选择你最喜欢的方法。
filter fghfilea ok fghreport ok notfghfile notok; mv --filter fghfilea jklfilea; mv
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter fghfilea "mv fghfilea jklfilea"
# Even better, automatically infers the file name
filter fghfilea ok fghreport ok notfghfile notok; auto --all --filter "mv fghfilea jklfilea"
多步骤的解决方案
要仔细查看命令是否执行良好,您可以键入以下命令:
filter fghfilea ok
filter fghfileb ok
filter fghfileb notok
当你确信过滤效果不错时,执行第一步:
mv fghfilea jklfilea
如果你想测试,并使用前面的筛选器,输入:
mv --test --filter
如果转换不是你想要的(例如,即使用mv——解释你看到的东西是错误的),你可以输入mv——clear重新启动移动文件,或添加更多的例子mv input1 input2,其中input1和input2是其他例子
当你有信心的时候,就打字
mv --filter
瞧!所有重命名都是使用筛选器完成的。
免责声明:我是这篇论文的合著者。可能很快还会有bash生成功能。