【Linuxコマンド】連番ファイルを番号指定で一括フォルダ移動させる方法
追記しました。更新日:2022年3月20日
今回は、Linuxコマンドを使い、ファイル名に付いている連番を用いて一括でフォルダ移動する方法のメモ。
【関連リンク】
上記リンクは mv *.csv 移動先フォルダ名/.
や mv ファイル1 ファイル2 移動先フォルダ名/.
のような方法について。
今回はもう少し高度な条件での一括移動方法です。
はじめに
スマホで撮影した画像ファイル名などには連番が付加してあるかと思います。我がスマホの画像ファイルには「DSC_0001.JPG」のようなゼロ埋め4桁の連番が自動でついている。
撮影した日付や場所ごとにフォルダ別けすることがよくありますが、たとえば
「0008~0021 の画像ファイルを○○フォルダに移したい」
という作業を、コマンドで movefiles 0008 0021 ○○フォルダ
とか出来たら楽そうです。
実行環境
作業フォルダとサンプルファイルの作成
- 作業フォルダの作成とそこへの移動
@~ $ mkdir test ; cd $_ ↩️ @test $
mkdir
コマンドでフォルダを作成し、cd
コマンドでそこへ移動しています。
;
(セミコロン) は改行の換わり。
cd
コマンド はディレクトリ変更コマンド。移動する時に使います。$_
は直前の変数の値を取り出す、という意味です。直前のcdコマンドで、引数にフォルダ名「test」を渡しましたが、$_
にはこの場合「test」が入っています。
ついでに確認、
- 直前の変数の値を見る
echoコマンドで $_
の変化を見ておきます。
@test $ echo hello ↩️ hello # 直前の変数に入っている値を表示 @test $ echo $_ ↩️ hello # 別の引数でコマンド実行 @test $ echo 'world !' ↩️ world ! # 直前の変数に入っている値を表示 @test $ echo $_ ↩️ world !
$_
の中身が直前のものに入れ替わっている事が確認できた。
- サンプルファイルの作成
連番の付いた空のファイルをサンプル用に作ります。空のファイルを作るには touch ファイル名
で出来ます。連番の場合の方法を2つ挙げておきます。
- ブレーズ展開を使う : 例 touch {001..050}.txt
- seqコマンドを使う: 例 touch
seq -f %03g.txt 1 50
1.ブレーズ展開を使う方法は、最も簡単。
@test $ ls ↩️ @test $ # 空です。作ったばかりのフォルダに入ったので。 # 連番の空ファイルを作成 @test $ touch sample_{001..015}.txt ↩️ @test $ # 作業フォルダの中身 @test $ ls ↩️ sample_001.txt sample_006.txt sample_011.txt sample_002.txt sample_007.txt sample_012.txt sample_003.txt sample_008.txt sample_013.txt sample_004.txt sample_009.txt sample_014.txt sample_005.txt sample_010.txt sample_015.txt @test $
簡単に連番ファイルが出来ました。
2. seqコマンドを使う方法
seqコマンドの簡単な使い方から見ていく。for文のような事ができるコマンド。
sequence(シーケンス) の略かな? 沖縄の飲み物です(嘘
- seqコマンドに引数を1つ渡す
# 引数に数字を1つ渡すと、 @test $ seq 5 ↩️ 1 2 3 4 5
- seqコマンドに引数を2つ渡す
# 引数に2つ数字を渡すと、 @test $ seq 3 7 ↩️ 3 4 5 6 7
- seqコマンドにオプション
-w
(小文字)と引数1つを渡す
# オプション -w (小文字) と数字1つ @test $ seq -w 11 ↩️ 01 02 03 04 05 06 07 08 09 10 11
2桁ゼロ埋めの連番が生成された。楽チン。
- オプション
-f
でフォーマット指定し、引数2つでゼロ埋め3桁連番
# ゼロ埋め3桁なら @test $ seq -f %03g 16 21 ↩️ 016 017 018 019 020 021
%03g
が「0埋め3桁」の意味になる。
file_%03g.txt 数字1 数字2
とすると、数字1~数字2 までの連番で、ゼロ埋め3桁の、「file_001.txt」のようなファイル名が生成される。
(あくまでも、ファイル名っぽい文字列が生成されただけです)。
touch
コマンド を組み合わせれば、それらのファイル名でファイル作成できそうです。
ならば、やってみるか、ファイル生成。
seqコマンド | xargs touch
で連番空ファイル作成
# 後ろにtouch コマンドをパイプで繋げる。xargsを使う。 # 連番で空のcsvファイルを作成 @test $ seq -f file_%03g.csv 16 25 | xargs touch ↩️ # フォルダの中身を確認 @test $ ls ↩️ file_016.csv file_025.csv sample_009.txt file_017.csv sample_001.txt sample_010.txt file_018.csv sample_002.txt sample_011.txt file_019.csv sample_003.txt sample_012.txt file_020.csv sample_004.txt sample_013.txt file_021.csv sample_005.txt sample_014.txt file_022.csv sample_006.txt sample_015.txt file_023.csv sample_007.txt file_024.csv sample_008.txt
CSVファイルが追加されている。
touch
コマンドを先に書く方法。
touch
`コマンド` で連番空ファイル作成
# touch `コマンド` のコマンドは バッククォートで囲む @test $ touch `seq -f XXX_%03g.md 555 560` ↩️ @test $ ls ↩️ XXX_555.md file_021.csv sample_007.txt XXX_556.md file_022.csv sample_008.txt XXX_557.md file_023.csv sample_009.txt XXX_558.md file_024.csv sample_010.txt XXX_559.md file_025.csv sample_011.txt XXX_560.md sample_001.txt sample_012.txt file_016.csv sample_002.txt sample_013.txt file_017.csv sample_003.txt sample_014.txt file_018.csv sample_004.txt sample_015.txt file_019.csv sample_005.txt file_020.csv sample_006.txt
たくさんできた。簡単。
空のファイルを大量生成する事が実際上行われているのであろうか?
ファイル検索の方法
2つ挙げておきます。(これしか知らない)
- ls
|
(パイプ) grep 検索条件・文字列 - findコマンド
ls |
grep 検索条件・文字列
ls
コマンド でフォルダの中身表示出力から、grep
コマンド で文字列・条件を抽出する方法です。
ls
とgrep
は|
(パイプ)で繋ぎます。条件にヒットした既存のファイル名が取得される。
grepコマンドの使い方
grep
コマンドは、ファイルの中身から文字列を検索したりする時に使います。文章中から電話番号だけ抽出するとか、メルアドを抜き出すとか。
grep 文字列 検索元ファイル名
のコマンドでできる。
一方今からやるように、何かのコマンド出力の中から文字列を検索するような時には、パイプで繋いでgrep
コマンドを使うこともできる。
いくつか例を挙げてみます。
- 特定の拡張子を抽出する
# フォルダの中身 @test $ ls ↩️ XXX_555.md file_021.csv sample_007.txt XXX_556.md file_022.csv sample_008.txt XXX_557.md file_023.csv sample_009.txt XXX_558.md file_024.csv sample_010.txt XXX_559.md file_025.csv sample_011.txt XXX_560.md sample_001.txt sample_012.txt file_016.csv sample_002.txt sample_013.txt file_017.csv sample_003.txt sample_014.txt file_018.csv sample_004.txt sample_015.txt file_019.csv sample_005.txt file_020.csv sample_006.txt # csvファイルのみ抽出 @test $ ls | grep 'csv' ↩️ file_016.csv file_017.csv file_018.csv file_019.csv file_020.csv file_021.csv file_022.csv file_023.csv file_024.csv file_025.csv
- 数字の1を含むファイル名を抽出
@test $ ls | grep 1 ↩️ file_016.csv file_017.csv file_018.csv file_019.csv file_021.csv sample_001.txt sample_010.txt sample_011.txt sample_012.txt sample_013.txt sample_014.txt sample_015.txt
- 008 と 016 を含むファイルを抽出
@test $ ls | grep -e '008' -e '016' ↩️ file_016.csv sample_008.txt
-e
オプション を検索文字列の前に付けています。それをいくつも追加すれば複数の検索条件を並べる事ができる。しかし面倒ですね。
003~014 を含むファイルを抽出してみます。この連番は、
- 003~009 :
00[3-9]
- 010~014 :
01[0-4]
の条件のどちからにヒットすれば良い。複数条件のor
検索。これの正規表現もパイプ( | )を使い、(条件1|条件2)
と表現します。
@test $ ls | grep -E '(00[3-9]|01[0-4])' ↩️ sample_003.txt sample_004.txt sample_005.txt sample_006.txt sample_007.txt sample_008.txt sample_009.txt sample_010.txt sample_011.txt sample_012.txt sample_013.txt sample_014.txt
繰り返しますが、-E
(大文字)オプションを付けると、正規表現で検索抽出できる。
パイプ( | ) で繋ぐと「または」の意味になり、複数に該当するものが抽出される。パイプは条件の数により幾つも使えます。
注意点ですが、今回の場合はたまたま指定の連番が「sample」から始まるファイルにしかありませんでしたが、フォルダや別の意図しないファイルにも含む場合はヒットしてしまいます。
そうならないように、正規表現をより限定した書き方 sample_(条件1|条件2).txt
のようにすればオーケー👌
ls
とgrep
で抽出した結果をmv
コマンドで移動させる
mv
コマンドはファイルやフォルダの名前の書き換えや移動をする時に使います。
単純にファイルを移動させたいときは、
- 1つのファイルを移動
mv ファイル名 移動先フォルダ名
- 複数のファイルを同じフォルダへ一括移動
mv ファイル1 名 ファイル2名 ファイル3名 移動先フォルダ名/.
でできる。
※ フォルダ名の後ろに「/.
」を付けているのは、移動先フォルダが存在しなかった場合の対策です。
この方法では複数ファイルの移動に何個もファイル名を書く必要があり面倒です。
mv *.csv 移動先フォルダ名/.
のような時は早い。カレントディレクトリ内の csvファイル が一括で移動できる。
さて、ここからが連番ファイルの一括移動方法です。
上でやった grep
検索抽出 のヒット結果に対して、xargs mv -t 移動先フォルダ名
を パイプ( | ) で繋ぐと、指定したフォルダへ結果のファイルを移動させることができる。
- 移動先フォルダの作成と、移動
003~014 までの連番ファイルを新規フォルダへ移動させます。
# 新規フォルダ作成 @test $ mkdir new_Folder ↩️ @test $ # 003~014 を含むファイルを新規フォルダへ移動 @test $ ls | grep -E '(00[3-9]|01[0-14])' | xargs mv -t new_Folder/ ↩️ @test $ # 何も起きない。移動できたかな? # 新規フォルダの中身を確認 @test $ ls new_Folder/ ↩️ sample_003.txt sample_007.txt sample_011.txt sample_004.txt sample_008.txt sample_014.txt sample_005.txt sample_009.txt sample_006.txt sample_010.txt @test $
作ったばかりのフォルダに移動できている!✨😍✨
# 元のフォルダ(カレント)の中身確認 @test $ ls ↩️ XXX_555.md file_018.csv new_Folder XXX_556.md file_019.csv sample_001.txt XXX_557.md file_020.csv sample_002.txt XXX_558.md file_021.csv sample_012.txt XXX_559.md file_022.csv sample_013.txt XXX_560.md file_023.csv sample_015.txt file_016.csv file_024.csv file_017.csv file_025.csv @test $
減ってる。移動できてる。やったー😃✌️
- 条件が限定的ならこっちの方法が簡単
@test $ ls ↩️ XXX_555.md file_018.csv new_Folder XXX_556.md file_019.csv sample_001.txt XXX_557.md file_020.csv sample_002.txt XXX_558.md file_021.csv sample_012.txt XXX_559.md file_022.csv sample_013.txt XXX_560.md file_023.csv sample_015.txt file_016.csv file_024.csv file_017.csv file_025.csv
mdファイルの 555~557 を新規フォルダへ移動させます。
@test $ mv XXX_{555..557}.md new_Folder/. ↩️ @test $ ls new_Folder/ ↩️ XXX_555.md sample_005.txt sample_010.txt XXX_556.md sample_006.txt sample_011.txt XXX_557.md sample_007.txt sample_014.txt sample_003.txt sample_008.txt sample_004.txt sample_009.txt @test $
この方法は、ファイル名を一部ではなく、完全に同じものを生成し、しかもgrep
コマンドなど使わず該当するかどうかの判断もしていない。
条件次第で書き方を変えて使うのが良いですね。毎回同じ事やファイルしか扱わないなら、ブレーズ展開に数字だけ指定して移動する方法で構わない。
ですが、この方法は条件に該当するファイル名を抽出する過程を経ていないため、ファイルが存在しない場合は以下のようなエラーが出る。
- 上記でコマンド実行で移動済みのファイルを再び移動させてみる
@test $ mv XXX_{555..557}.md new_Folder/. ↩️ mv: cannot stat 'XXX_555.md': No such file or directory mv: cannot stat 'XXX_556.md': No such file or directory mv: cannot stat 'XXX_557.md': No such file or directory
そんなファイルやフォルダは無え! と怒られた。
追記 これで行ける
【追記】
上記にseq
コマンドの使い方を書きましたが、次のようにできるのを発見した。
- まずは普通の
@~ $ seq 3 ↩️ 1 2 3 @~ $
連番が縦に連なっている。
セパレータ文字がデフォルトで「改行」になっているためだ。
そこで、
- セパレータ(区切り文字)を変える
@~ $ seq -s , 3 ↩️ 1,2,3 @~ $
デフォルトでセパレータが「改行」だったのが、オプション-s
でセパレータを変えることで リスト のように表示された。
seq -s 区切り文字 数字
と書けばよい。
上の書き方では、スペース を区切り文字にしたい時に不都合なので、区切り文字
は クォート '
で囲む。
- 区切り文字いろいろ
# カンマ区切り、数字2つ @~ $ seq -s ',' 3 8 ↩️ 3,4,5,6,7,8 @~ $ # スペース区切り、数字3つ (120~150で10ずつ飛び飛び) @~ $ seq -s ' ' 120 10 150↩️ 120 130 140 150 @~ $
ここから注目。ゼロ埋めで数字を与えるとどうなるだろうか?
- パイプ区切り、数字2つ(ゼロ埋め3桁)
@~ $ seq -s '|' 001 003 1|2|3 @~ $
ゼロが消えた。
そしたら、オプション-f
を追加してフォーマットを指定すれば行けるのではないか。
- パイプ区切り、ゼロ埋めフォーマット指定、数字2つ
@~ $ seq -s '|' -f %03g 001 003 ↩️ 001|002|003 @~ $
行ける!
おっ? この形は上で見ましたね?
grep
コマンドの正規表現 で使えそうではないか?! 抽出条件を複数渡すときに パイプ( | ) で繋いだアレ。
seq -E '(正規表現1|正規表現2)'
という形にすればよいのだ。
seq -E '(001|002|003|004|005)'
とかでも構わないのだから、次のように書けば、数字2つで連番の抽出ができる筈だ。
- これだ!正規表現での抽出ヒットファイルを表示
フォルダの中身を確認してから
@test $ ls ↩️ XXX_558.md file_020.csv sample_001.txt XXX_559.md file_021.csv sample_002.txt XXX_560.md file_022.csv sample_012.txt file_016.csv file_023.csv sample_013.txt file_017.csv file_024.csv sample_015.txt file_018.csv file_025.csv file_019.csv new_Folder @test $ # これだ! @test $ ls | grep -E `seq -s '|' -f %03g 023 600` ↩️ XXX_558.md XXX_559.md XXX_560.md file_023.csv file_024.csv file_025.csv @test $
出来た‼️
あとは、これを上でやったように mv
コマンド に渡せば、開始と終了の番号指定で連番ファイルが一括移動できる。
引数2つで該当する連番ファイルを抽出できたので、シェルスクリプトか bashrc
のalias
にして、フォルダ名を含む引数の受け渡しが出来れば完全。
【追記おわり】
長くなった。find
コマンドによる連番一括移動は次の機会に。
以上です。