Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/file/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/unix/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
File Unix中基于模式重命名多个文件_File_Unix_Rename_Batch Rename - Fatal编程技术网

File Unix中基于模式重命名多个文件

File Unix中基于模式重命名多个文件,file,unix,rename,batch-rename,File,Unix,Rename,Batch Rename,目录中有多个文件以前缀fgh开头,例如: fghfilea fghfileb fghfilec file001abc.txt -> abc1.txt ofile0002abcd.txt -> abcd2.txt ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print arr[0] " " arr[2] arr[1] }'|xargs -l mv 我想将它们全部重命名为前缀jkl。是否有

目录中有多个文件以前缀
fgh
开头,例如:

fghfilea
fghfileb
fghfilec
file001abc.txt -> abc1.txt
ofile0002abcd.txt -> abcd2.txt 

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print   arr[0]  " "  arr[2] arr[1] }'|xargs  -l mv

我想将它们全部重命名为前缀
jkl
。是否有一个命令来执行此操作,而不是单独重命名每个文件?

有几种方法,但使用
重命名可能是最简单的方法

使用一个版本的:

使用的其他版本(与相同):


您应该查看平台的手册页,看看上面哪一项适用。

这就是如何将
sed
mv
一起使用来进行重命名:

rename fgh jkl fgh*
for f in fgh*; do mv "$f" $(echo "$f" | sed 's/^fgh/jkl/g'); done
根据下面的注释,如果文件名中有空格,则可能需要在返回要将文件移动到的名称的子函数周围加引号:

for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done

重命名可能不在每个系统中。所以如果你没有,就用外壳 此示例在bashshell中实现

for f in fgh*; do mv "$f" "${f/fgh/xxx}";done

有很多方法可以做到这一点(并非所有这些方法都适用于所有unixy系统):

  • ls | cut-c4-| xargs-I§mv fgh§jkl§

    §可由您认为方便的任何内容替代。您也可以使用
    find-exec
    来实现这一点,但在许多系统上,这一点的行为都有细微的不同,因此我通常避免使用这种方式

  • fgh*中f的
    ;做mv“$f”“${f/fgh/jkl}”;完成

    正如他们所说的,粗糙但有效

  • rename's/^fgh/jkl/'fgh*

    非常漂亮,但是重命名在BSD上不存在,BSD是afaik中最常见的unix系统

  • 重命名fgh jkl fgh*

  • ls | perl-ne'chomp;其次,除非-e$o=$\u0;s/fgh/jkl/;下一个if-e;重命名$o,$"

    如果您坚持使用Perl,但系统上没有重命名,那么您可以使用这个怪物

其中一些有点复杂,列表还远未完成,但您可以在这里找到几乎所有unix系统所需的内容。

要安装Perl脚本,请执行以下操作:

如Stephan202回答中的评论所述。 基于Debian的发行版具有相同的功能。Redhat/rpm发行版具有相同的功能。

OSX默认情况下没有安装一个(至少在10.8中是这样),Windows/Cygwin也没有

这里有一种使用命令行Groovy的方法:

groovy-e'新文件(“.”).eachFileMatch(~/fgh.*/){it.renameTo(it.name.replaceFirst(“fgh”,“jkl”))}'
使用:


一旦您满意输出看起来正确,请删除
--dry run
标志。

我建议使用我自己的脚本,这样可以解决此问题。它还可以选择更改文件名的编码,并将组合变音符号转换为预合成字符,这是我从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);
  }
}
使用:

使用通过示例进行处理的工具(windows和Linux bash):

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea
# for your fgh example. renames all files from "fgh..." to "jkl..."
files = Dir['fgh*']

files.each do |f|
  f2 = f.gsub('fgh', 'jkl')
  system("mv #{f} #{f2}")
end

# renames all files in directory from "021roman.rb" to "021_roman.rb"
files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/}

files.each do |f|
  f1 = f.clone
  f2 = f.insert(3, '_')
  system("mv #{f1} #{f2}")
end
它首先根据示例计算过滤器,其中输入是文件名和输出(ok和NOOK,任意字符串)。如果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--explain
您也会发现有问题),您可以键入
mv--clear
重新开始移动文件,或者添加更多示例
mv input1 input2
,其中input1和input2是其他示例

当你自信时,只需打字

mv --filter
瞧!所有重命名都是使用过滤器完成的

免责声明:我是这部为学术目的而创作的作品的合著者。很快也可能会有一个bash生成功能。

在Ruby中这样做(在我的Mac上)要容易得多。以下是两个示例:

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea
# for your fgh example. renames all files from "fgh..." to "jkl..."
files = Dir['fgh*']

files.each do |f|
  f2 = f.gsub('fgh', 'jkl')
  system("mv #{f} #{f2}")
end

# renames all files in directory from "021roman.rb" to "021_roman.rb"
files = Dir['*rb'].select {|f| f =~ /^[0-9]{3}[a-zA-Z]+/}

files.each do |f|
  f1 = f.clone
  f2 = f.insert(3, '_')
  system("mv #{f1} #{f2}")
end

使用
find
xargs
sed

find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"'
它比以前更复杂,但是它允许递归地重命名文件。比如说结构,

.
├── fghdir
│   ├── fdhfilea
│   └── fghfilea
├── fghfile\ e
├── fghfilea
├── fghfileb
├── fghfilec
└── other
    ├── fghfile\ e
    ├── fghfilea
    ├── fghfileb
    └── fghfilec
会变成这样,

.
├── fghdir
│   ├── fdhfilea
│   └── jklfilea
├── jklfile\ e
├── jklfilea
├── jklfileb
├── jklfilec
└── other
    ├── jklfile\ e
    ├── jklfilea
    ├── jklfileb
    └── jklfilec

使其与xargs一起工作的关键是。

重命名海量文件的我的版本:

for i in *; do
    echo "mv $i $i"
done |
sed -e "s#from_pattern#to_pattern#g” > result1.sh
sh result1.sh

在Solaris上,您可以尝试:

for file in `find ./ -name "*TextForRename*"`; do 
    mv -f "$file" "${file/TextForRename/NewText}"
done

这对我使用regexp有效:

我希望将文件重命名为如下所示:

file0001.txt -> 1.txt
ofile0002.txt -> 2.txt 
f_i_l_e0003.txt -> 3.txt
使用[a-z | |]+0*([0-9]+.)regexp,其中([0-9]+.)是要在重命名命令上使用的组子字符串

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)/, arr) { print   arr[0]  " "  arr[1] }'|xargs  -l mv
产生:

mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt
  mv file001abc.txt abc1.txt
  mv ofile0002abcd.txt abcd2.txt 
另一个例子:

fghfilea
fghfileb
fghfilec
file001abc.txt -> abc1.txt
ofile0002abcd.txt -> abcd2.txt 

ls -1 | awk 'match($0, /[a-z|\_]+0*([0-9]+.*)([a-z]+)/, arr) { print   arr[0]  " "  arr[2] arr[1] }'|xargs  -l mv
产生:

mv file0001.txt 1.txt
mv ofile0002.txt 2.txt
mv f_i_l_e0003.txt 3.txt
  mv file001abc.txt abc1.txt
  mv ofile0002abcd.txt abcd2.txt 

警告,小心。

我编写此脚本是为了递归地搜索所有.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;

在文件列表上运行
sed
表达式的通用脚本(与结合):

通过传递脚本a
sed
表达式,然后传递任何文件列表来调用,就像以下版本一样:


您也可以使用下面的脚本。这是非常容易在终端上运行

//一次重命名多个文件

for file in  FILE_NAME*
do
    mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}"
done
示例:-

for file in  hello*
do
    mv -i "${file}" "${file/hello/JAISHREE}"
done
另一种可能:

fgh*中f的
;do mv--“$f”jkl${f:3}”;完成

此脚本适用于递归重命名,目录/文件名可能包含
for file in  FILE_NAME*
do
    mv -i "${file}" "${file/FILE_NAME/RENAMED_FILE_NAME}"
done
for file in  hello*
do
    mv -i "${file}" "${file/hello/JAISHREE}"
done
find . -type f -name "*\;*" | while read fname; do
    dirname=`dirname "$fname"`
    filename=`basename "$fname"`
    newname=`echo "$filename" | sed -e "s/;/ /g"`
    mv "${dirname}/$filename" "${dirname}/$newname"
done