web-dev-qa-db-ja.com

Unixのパターンに基づいて複数のファイルの名前を変更する

ディレクトリ内にプレフィックスfghで始まるファイルが複数あります。次に例を示します。

fghfilea
fghfileb
fghfilec

それらすべてを接頭辞jklで始まる名前に変更したいです。各ファイルを個別に名前変更する代わりに、それを実行するための単一のコマンドはありますか?

215
john

いくつかの方法がありますが、renameを使用するのがおそらく最も簡単でしょう。

rename の1つのバージョンを使用する:

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

別のバージョンの rename を使用する( Judy2K's answer と同じ):

rename fgh jkl fgh*

あなたはあなたのプラットフォームのmanページをチェックして上記のどれが当てはまるかを確かめるべきです。

258
Stephan202

これはsedmvを一緒に使用して名前を変更する方法です。

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
103
nik

名前の変更はすべてのシステムにあるわけではありません。あなたがそれを持っていないのであれば、bashシェルでシェルこの例を使用してください

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

mmv を使う:

mmv "fgh*" "jkl#1"
36
Lee Netherton

それをするには多くの方法があります(これらのすべてがすべてのunixyシステムで動作するわけではありません):

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

    §はあなたが便利だと思うものなら何でも取り替えることができます。あなたはfind -execでもこれを行うことができますが、それは多くのシステムで微妙に異なる振る舞いをするので、私は通常それを避けます

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

    彼らは言うように粗いが効果的

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

    本当に可愛いですが、renameはBSDには存在しません。これは最も一般的なUNIXシステムです。

  • rename fgh jkl fgh*

  • ls | Perl -ne 'chomp; next unless -e; $o = $_; s/fgh/jkl/; next if -e; rename $o, $_';

    Perlの使用を主張していても、システムに名前の変更がない場合は、このモンスターを使用できます。

それらのいくつかは少し複雑で、リストは完全には程遠いです、しかし、あなたはここであなたがほしいほとんどすべてのUNIXシステムのために欲しいものを見つけるでしょう。

19
iwein
rename fgh jkl fgh*
13
Judy2K

findxargs、およびsedを使用します。

find . -name "fgh*" -type f -print0 | xargs -0 -I {} sh -c 'mv "{}" "$(dirname "{}")/`echo $(basename "{}") | sed 's/^fgh/jkl/g'`"'

@ nikの解決策 よりも複雑ですが、ファイルの名前を再帰的に変更することができます。たとえば、

.
├── 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で動作させるための鍵は、 xargsからシェルを呼び出す です。

8
luissquall

Perl 名前変更 スクリプトをインストールするには:

Sudo cpan install File::Rename

Stephan202の回答のコメントにあるように、 2つの名前変更 があります。 Debianベースのディストリビューションは Perl rename を持っています。 Redhat/rpmディストリビューションには、 C rename があります。
OS Xにはデフォルトではインストールされていません(少なくとも10.8では)。Windows/ Cygwinもインストールされていません。

3
Sam Inverso

これは、コマンドラインのGroovyを使ってそれを行う方法です。

groovy -e 'new File(".").eachFileMatch(~/fgh.*/) {it.renameTo(it.name.replaceFirst("fgh", "jkl"))}'
2
jesseplymale

Solarisでは、次のことができます。

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

#replace all files ended witn .f77 to .f90 in a directory

for filename in *.f77
do 
    #echo $filename
    #b= echo $filename | cut -d. -f1
    #echo $b    
    mv "${filename}" "${filename%.f77}.f90"    
done
2
Suragini

私はこの問題を解決する私自身のスクリプトを使うことを勧めます。ファイル名のエンコーディングを変更したり、発音区別符号を組み合わせて変換したりするオプションもあります。これは、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);
  }
}
1

Rubyでこれをする方がずっと簡単でした(私のMac上)。これが2つの例です。

# 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
1
Raymond Gan

私のバージョンの大容量ファイルの名前変更:

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

リネーム を使う:

$ renamer --find /^fgh/ --replace jkl * --dry-run

出力が正しければ、--dry-runフラグを削除します。

1
Lloyd

例で処理する 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 --explainでも何か問題があることがわかります)、mv --clearと入力してファイルの移動を再開するか、さらにmv input1 input2を追加することができます。ここでinput1とinput2は他の例です。

自信があるときは、ただ入力するだけです。

mv --filter

そしてほら!名前の変更はすべてフィルタを使用して行われます。

免責事項:私は学術目的のために作られたこの作品の共著者です。まもなくbashを生み出す機能もあるかもしれません。

1
Mikaël Mayer

このスクリプトを書いて、見つかったファイルの名前を再帰的に.aviに変更し、すべての.mkvファイルを検索します。あなたのニーズに合わせてカスタマイズできます。ファイルパスからファイルディレクトリ、拡張子、ファイル名を取得するなど、将来的に参照する必要がある場合を含めて、他にもいくつか追加しました。

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;
0
David Okwii

これはregexpを使って私のために働きました:

ファイルの名前を次のように変更したいと思いました。

file0001.txt -> 1.txt
ofile0002.txt -> 2.txt 
f_i_l_e0003.txt -> 3.txt

[a-z | _] + 0 *([0-9] + .)正規表現ここで、([0-9] +。)は、renameコマンドで使用するグループサブストリングです。

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

もう一つの例:

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 file001abc.txt abc1.txt
  mv ofile0002abcd.txt abcd2.txt 

警告、注意してください。

0
Steven Lizarazo

もう一つの可能​​な パラメータ展開

for f in fgh*; do mv -- "$f" "jkl${f:3}"; done
0
PesaThe

ファイルのリストに対してsed式を実行するための一般的なスクリプト( sed solutionrename solution を組み合わせたもの):

#!/bin/sh

e=$1
shift

for f in $*; do
    fNew=$(echo "$f" | sed "$e")
    mv "$f" "$fNew";
done

sed のバージョンのように、スクリプトにrename式を渡し、次に任意のファイルリストを渡して呼び出します。

script.sh 's/^fgh/jkl/' fgh*
0
palswim

下記のスクリプトを使用することもできます。それは非常に端末上で実行するのは簡単です...

//複数のファイルの名前を同時に変更

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
0
Sanjay Singh