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


248

fghたとえば、次のように、prefix で始まるディレクトリに複数のファイルがあります。

fghfilea
fghfileb
fghfilec

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


1
ここで確認してください。theunixshell.blogspot.com/2013/01/...
ビジェイ

回答:


289

いくつかの方法がありますが、renameおそらく最も簡単に使用できます。

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

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

別のバージョンの使用renameJudy2Kの回答と同じ):

rename fgh jkl fgh*

上記のどれが当てはまるかについては、プラットフォームのマニュアルページを確認してください。


7
+1名前の変更さえも知りませんでした... mvとsedでforループの使用をやめることができます...ありがとうございます!
balpha 2009

2
あなたは別のものにリンクしていますしrename、あなたはunixhelp.ed.ac.uk/CGI/man-cgi?renameの構文を示しています
名前

7
すべての* nixシステムに存在するわけではありません。Max OS Xにはありませんし、それを取得するためのfinkのパッケージもありません。MacPortsを見たことがない。
dmckee ---元モデレーターの子猫

6
AFAICTはrename、Linux固有のスクリプトまたはユーティリティのようです。移植性を気にする場合は、引き続きsedandループまたはインラインPerlスクリプトを使用してください。
D.Shawley 09

33
brew install renameOS Xでは:)
sam

117

これは方法でsedあり、mv一緒に使用して名前を変更できます。

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

1
とても近い。最初に出現するfghにのみ一致させたいことに注意してください: 's / ^ fgh / jkl / g'(キャレットはすべての違いを生み出します)。
Stephan202 2009

2
正確を期すために...「名前の最初のfgh」を意味し、「fghの最初の出現」ではありません。/ ^ fgh /は "fghi"に一致しますが、 "efgh"には一致しません。
Dave Sherohman、2009

@Stephan、それは私の部分のタイプミスでした(修正しました)。
nik 07

5
「名前の変更」にアクセスできない場合は、これでうまくいきます。ファイル名にスペースが含まれている場合、コードで引用符が必要になる場合があります。for f in fgh*; do mv "$f" "$(echo $f | sed 's/^fgh/jkl/g')"; done
Dave Nelson

1
@nik引用符なしでこのファイルリストの名前を変更すると、エラーがスローされますtouch fghfilea fghfileb fghfilec fghfile\ d。@DaveNelsonのコメントを考慮に入れることをお勧めします。
luissquall 2014年

75

名前変更はすべてのシステムにあるとは限りません。持っていない場合は、bashシェルでこの例のシェルを使用してください

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

1
このソリューションでは、sedコマンドは必要ありません。これは@nikの答えよりも簡単です。
ハリル2016

xxxは置換を表しますか?元のポスターの場合、それは「jkl」
でした

1
それらすべての最もクリーンなソリューション。
MTヘッド

3
おそらくこれは、POSIX shまたは一般的に他のシェルには存在しないBash拡張であることをより強調して指摘します。
Tripleee

甘い-Unixの世界には非常に多くのあいまいなコーナーがあります-これをこれまでに見たことがない。
wcochran

40

mmvの使用:

mmv "fgh*" "jkl#1"

1
うわー、これは問題を解決する優れた簡単な方法です!mmvをご紹介していただき、ありがとうございます。
ヘンデカ2014年

1
ありがとう!!! これまでmmvについて聞いたことがありません。インストールして遊んでいるだけ-シンプルでパワフル。
Nick Rice

3
名前を再帰的にバッチ処理する場合;は、と組み合わせて使用し#1ます。例:mmv ";fgh*" "#1jkl#2"
Alp

非常にエレガントなソリューション!
フェルマーのリトルスチューデント

1
まさに私が必要としたもの。' 'でグループをキャプチャし、#1、#2、...でコールバックします。例:mmv "my show ep 1080p。*" "my.show。#1.#2" = my.show.001.avi
ランディ

20

これを行うには多くの方法があります(これらのすべてがすべての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*

    かなりきれいですが、BSDには名前の変更がありません。これは、最も一般的なUNIXシステムのafaikです。

  • rename fgh jkl fgh*

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

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

それらのいくつかは少し複雑で、リストは完全とはほど遠いですが、ほとんどすべてのUNIXシステムで必要なものが見つかります。


2
こういうモンスター大好き!
lefakir 2013

ええ、私はまだperlにも弱点があります:)
iwein


ここにあるPerlモンスターは、ファイル名にスペースが含まれていると問題なく機能します。
mlerley

13
rename fgh jkl fgh*

6
私のマシンでは、これによりエラーが発生します。
Stephan202 2009

@ Stephan202、あなたのマシンは何ですか?
nik 07

Ubuntu 8.10(perl v5.10.0 / 2009-06-26)
Stephan202

@ Stephan202同じ問題がありますが、解決しましたか?(7年後)
whossname

1
@whossname:すみません、本当に思い出せません。(休日のため返信が遅くなります。)
Stephan202

8

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からシェル呼び出すことです。


1
私はこのようなものを投稿するつもりでしたが、適切なコマンドを取得するのに1時間
Juan Mendes

3

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

sudo cpan install File::Rename

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


3

コマンドラインのGroovyを使用してこれを行う方法を次に示します。

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

2

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

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

ループ内でファイル名を引用すると半分のポイントになりますfor file in $(find)が、根本的に欠陥があり、引用で修正することはできません。場合はfind戻り./file name with spacesますが取得するfor上でループを./filenamewith、およびspaces、ループ内で引用のない量が助けない(あるいは必要になること)します。
tripleee

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

このスクリプトは、空白を含む可能性のあるディレクトリ/ファイル名を使用して再帰的に名前を変更するのに役立ちました。

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

sedこの例ではのすべての出現箇所;をスペースで置き換える式に注意してください。もちろん、これは特定のニーズに応じて置き換える必要があります。


どうもありがとう !素晴らしい脚本
Walter Schrabmair

1

例で処理するStringSolverツール(windowsおよびLinux bash)の使用:

filter fghfilea ok fghreport ok notfghfile notok; mv --all --filter fghfilea jklfilea

まず、examples基づいてフィルターを計算します。ここで、入力はファイル名と出力です(okおよびnotok、任意の文字列)。filterにオプション--autoがある場合、またはこのコマンドの後に単独で呼び出された場合は、フォルダーokとフォルダーが作成され、notokそれぞれにファイルがプッシュされます。

次に、フィルターを使用して、mvコマンドは半自動移動で、修飾子--autoで自動になります。--filterする前のフィルタのおかげを使用して、それからのマッピングを発見fghfileaするjklfileaと、すべてのフィルタのファイルにそれを適用します。


その他の1行ソリューション

同じことを行う他の同等の方法(各行は同等)なので、好きな方法を選択できます。

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

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

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

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

スクリプトを実行する前に確認できることが好きです
ardochhigh

これは、スペース、引用符、またはその他のシェルメタ文字を含むファイル名で見事に機能しなくなります。
tripleee

1

この問題を解決する独自のスクリプトを使用することをお勧めします。また、ファイル名のエンコーディングを変更したり、発音区別記号を合成済み文字に変換したりするオプションもあります。これは、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);
  }
}

2
リンクのみの回答は推奨されないことに注意してください。SOの回答は、ソリューションの検索のエンドポイントである必要があります。参照としてリンクを維持しながら、ここにスタンドアロンの概要を追加することを検討してください。
kleopatra 2013年

@kleopatraによって予測されたように、リンクが取得されましたstale over time
y2k-shubham

1
@ y2k-shubham、もうありません。
アンドレ・フォン・Kugland

0

これは正規表現を使用して私のために働きました:

ファイルの名前を次のように変更したいのですが。

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

[az | _] + 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

このスクリプトを作成して、すべての.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;

0

実行するための汎用スクリプトsedファイルのリストにある式を(組み合わせたsedソリューションrename解決策を):

#!/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

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

//一度に複数のファイルの名前を変更します

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.