sedを使用してファイルの名前を一括変更


89

目的

これらのファイル名を変更します。

  • F00001-0708-RG-biasliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF-hioulgigl

これらのファイル名に:

  • F0001-0708-RG-biasliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF-hioulgigl

シェルコード

テストする:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'

実行するには:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh

私の質問

sedのコードがわかりません。置換コマンドが何であるかを理解しています

$ sed 's/something/mv'

手段。そして、正規表現はある程度理解できます。しかし、私はここで何が起こっているのか理解していません:

\(.\).\(.*\)

またはここ:

& \1\2/

前者は、私には、「単一の文字、単一の文字、単一の文字の任意の長さのシーケンス」を意味するように見えますが、確かにそれ以上のものがあります。後半まで:

& \1\2/

何も思いつきません。


回答:


152

まず、これを行う最も簡単な方法は、prenameコマンドまたはrenameコマンドを使用することです。

Ubuntu、OSX(Homebrewパッケージrename、MacPortsパッケージp5-file-rename)、またはperlの名前変更(prename)を使用するその他のシステムの場合:

rename s/0000/000/ F0000*

または、RHELなどのutil-linux-ngから名前が変更されたシステムの場合:

rename 0000 000 F0000*

これは、同等のsedコマンドよりもはるかに理解しやすいです。

ただし、sedコマンドの理解については、sedのマンページが役立ちます。man sedを実行して&を検索すると(/コマンドを使用して検索)、s / foo / bar / replacementsの特殊文字であることがわかります。

  s/regexp/replacement/
         Attempt  to match regexp against the pattern space.  If success‐
         ful,  replace  that  portion  matched  with  replacement.    The
         replacement may contain the special character & to refer to that
         portion of the pattern space  which  matched,  and  the  special
         escapes  \1  through  \9  to refer to the corresponding matching
         sub-expressions in the regexp.

したがって、\(.\)で参照できる最初の文字と一致し\1ます。次に.、常に0である次の文字と一致します。次に\(.*\)\2。で参照できるファイル名の残りの部分と一致します。

置換文字列は、&(元のファイル名)を使用してすべてをまとめます\1\2。これは、0であった2番目の文字を除くファイル名のすべての部分です。

これは、これを行うためのかなり不可解な方法です、私見。何らかの理由でrenameコマンドが使用できず、sedを使用して名前を変更したい場合(または、名前を変更するには複雑すぎることを行っていた場合)、正規表現でより明示的にすると、はるかに読みやすくなります。おそらく次のようなものです:

ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh

s / search / replace /で実際に何が変更されているかを確認できるため、読みやすくなります。また、誤って2回実行した場合でも、ファイル名から文字が吸い出され続けることはありません。


1
私のRHELサーバーでは、名前変更の構文は「rename 0000 000 F0000 *」になります
David LeBauer 2010

1
それrename自体が「名前が変更された」リンクである可能性が最も高いです。つまりはrenameされています「と改名」からprenameのUbuntuで..例えば:readlink -f $(which rename)出力/usr/bin/prename...renameで述べたデビッドは、全く別のプログラムです。
Peter.O 2012

1
良い点、ピーター。両方の名前変更ユーティリティに対処するために回答を更新しました。
エドワードアンダーソン

3
これをデバッグするには、最後にパイプをshに削除します。コマンドは画面にエコーアウトします。
ベンマシューズ2014年

1
ランダムなデータをパイプすることをお勧めしshますか?任意のコードが実行される可能性があるため、これは潜在的に危険です(データをコードとして扱っています)。
gniourf_gniourf 2016

46

sedの説明がありました。これで、シェルだけを使用でき、外部コマンドは必要ありません。

for file in F0000*
do
    echo mv "$file" "${file/#F0000/F000}"
    # ${file/#F0000/F000} means replace the pattern that starts at beginning of string
done

1
いいですが、括弧で参照することはできません。
Leonidas Tsampros 2013年

28

sed数年前に、バッチの名前変更の例を含む小さな投稿を書きました。

http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/

例えば:

for i in *; do
  mv "$i" "`echo $i | sed "s/regex/replace_text/"`";
done

正規表現は、(例えばグループが含まれている場合\(subregex\)、あなたはとして置換テキストでそれらを使用することができます\1\\2など


リンクのみの回答は推奨されないことに注意してください(リンクは時間の経過とともに古くなる傾向があります)。回答を編集して、ここに概要を追加することを検討してください。
kleopatra 2013年

それほど効率的ではありませんが、数百のファイルに対して作業を完了します。賛成。
VarunChandak20年

23

最も簡単な方法は次のとおりです。

for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done

または、移植可能に、

for i in F00001*; do mv "$i" "F0001${i#F00001}"; done

これF00001により、ファイル名のプレフィックスがF0001。に置き換えられます。ここでmaheshのクレジット:http://www.debian-administration.org/articles/150


3
変数の補間を適切に引用する必要があります。mv "$i" "${i/F00001/F0001}"。しかし、1
tripleee

7

sedコマンド

s/\(.\).\(.*\)/mv & \1\2/

交換する手段:

\(.\).\(.*\)

と:

mv & \1\2

通常のsedコマンドと同じです。ただし、括弧&\nマーカーは少し変更します。

検索文字列は、最初の1文字と一致し(パターン1として記憶され)、その後に1文字が続き、その後に残りの文字列(パターン2として記憶されます)が続きます。

置換文字列では、これらの一致したパターンを参照して、置換の一部として使用できます。一致した部分全体をとして参照することもでき&ます。

したがって、そのsedコマンドが実行しているのはmv、元のファイル(ソース用)と文字1および3以降に基づいてコマンドを作成し、文字2(宛先用)を効果的に削除することです。次の形式に沿って一連の行が表示されます。

mv F00001-0708-RG-biasliuyda F0001-0708-RG-biasliuyda
mv abcdef acdef

等々。


1
これは良い説明でしたが、sedコマンドを他のコマンドと一緒に使用して実際にファイルの名前を変更する方法を指摘すると役立つ場合があります。例:ls | sed "s/\(.\).\(.*\)/mv & \1\2/" | bash
jcarballo 2014年

@jcarballo:解析しls、パイプスルーしてsedからシェルをパイプスルーするのは危険です!偽造されたファイル名で任意のコードが実行される可能性があります。問題は、データをデータとして扱う必要があることです。ここでは、通常、何の予防措置もなしにコードにシリアル化されます。paxdiabloがこの回答を削除してくれるといいのですが、それは実際には良い習慣を示していないからです。(この質問に出くわしたのは、初心者| shが機能しなかったコマンドの後でランダムにパイプを使用し、この質問を見て回答がうまくいくと思ったためです:)。恐ろしいです!)。
gniourf_gniourf 2016

3

バックスラッシュパレンのものは、「パターンを一致させながら、ここで一致するものを保持する」ことを意味します。後で、置換テキスト側で、「\ 1」(最初の括弧で囲まれたブロック)、「\ 2」(2番目のブロック)などでそれらの記憶されたフラグメントを取り戻すことができます。


1

実際に行っているのが2番目の文字を削除することだけである場合は、それが何であるかに関係なく、次のようにすることができます。

s/.//2

しかし、あなたのコマンドはコマンドを構築し、mv実行のためにそれをシェルにパイプします。

これはあなたのバージョンよりも読みやすくありません:

find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh

find各ファイル名の前に「./」が付いているため、4番目の文字は削除されています。


この回答を削除していただければ幸いです。OPの非常に特殊なケースでは良かったかもしれませんが、このような答えを見て理解できない人が多く、| sh機能しないコマンドをランダムにパイプして、機能することを期待しています。より良い。恐ろしいです!(さらに、それは良い習慣ではありません)。ご理解いただければ幸いです。
gniourf_gniourf 2016

1

perlの名前変更の使用(ツールボックスにある必要があります):

rename -n 's/0000/000/' F0000*

-n出力の名前を実際に変更するのに適しているように見える場合は、スイッチを取り外します。

警告 これを実行できる場合とできない場合がある同じ名前の他のツールがあるので、注意してください。

util-linuxパッケージの一部であるrenameコマンドはそうではありません。

次のコマンドを実行した場合(GNU

$ rename

ご覧のとおりperlexpr、これは適切なツールのようです。

そうでない場合は、それをデフォルト(通常はすでにそうです)にしDebian、次のような派生物にしUbuntuます:

$ sudo apt install rename
$ sudo update-alternatives --set rename /usr/bin/file-rename

archlinuxの場合:

pacman -S perl-rename

RedHatファミリーディストリビューションの場合:

yum install prename

'prename'パッケージはEPELリポジトリにあります。


Gentooの場合:

emerge dev-perl/rename

* BSDの場合:

pkg install gprename

または p5-File-Rename


Macユーザーの場合:

brew install rename

別のディストリビューションでこのコマンドを使用していない場合は、パッケージマネージャーを検索してインストールするか、手動で実行してください

cpan -i File::Rename

古いスタンドアロンバージョンはここにあります


男の名前を変更


このツールは元々、Perlのお父さんであるLarryWallによって書かれました。



0
 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash

恐ろしい!任意のコードが実行される可能性があります(質問の特定のコンテキストではないかもしれませんが、このような答えを見て、そのように見えるものをランダムに入力しようとする人はたくさんいますが、それは恐ろしい危険です!)。この回答を削除していただければ幸いです(さらに、私が賛成した別の良い回答がここにあります)。
gniourf_gniourf 2016

0

これが私がすることです:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done

それで問題ないようであれば| sh、最後に追加します。そう:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done | sh

0

私のために働くいくつかの例:

$ tree -L 1 -F .
.
├── A.Show.2020.1400MB.txt
└── Some Show S01E01 the Loreming.txt

0 directories, 2 files

## remove "1400MB" (I: ignore case) ...

$ for f in *; do mv 2>/dev/null -v "$f" "`echo $f | sed -r 's/.[0-9]{1,}mb//I'`"; done;
renamed 'A.Show.2020.1400MB.txt' -> 'A.Show.2020.txt'

## change "S01E01 the" to "S01E01 The"
## \U& : change (here: regex-selected) text to uppercase;
##       note also: no need here for `\1` in that regex expression

$ for f in *; do mv 2>/dev/null "$f" "`echo $f | sed -r "s/([0-9] [a-z])/\U&/"`"; done

$ tree -L 1 -F .
.
├── A.Show.2020.txt
└── Some Show S01E01 The Loreming.txt

0 directories, 2 files
$ 

-1
for i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done

4
SOへようこそ。コードの説明を追加することを検討してください。それは他のユーザーがそれを理解するのに役立ちます。
DigvijayS20年

この答えは良いですが、上記の非常に賛成の答えのほぼ重複した答えです。
EricLeschinski20年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.