よちよちpython

独習 python/Qpython/Pydroid3/termux/Linux

【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つ挙げておきます。

  1. ブレーズ展開を使う : 例 touch {001..050}.txt
  2. 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つ挙げておきます。(これしか知らない)

  1. ls |(パイプ) grep 検索条件・文字列
  2. findコマンド


ls | grep 検索条件・文字列

lsコマンド でフォルダの中身表示出力から、grepコマンド で文字列・条件を抽出する方法です。

lsgrep|(パイプ)で繋ぎます。条件にヒットした既存のファイル名が取得される。



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 のようにすればオーケー👌



lsgrepで抽出した結果を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つで該当する連番ファイルを抽出できたので、シェルスクリプトbashrcalias にして、フォルダ名を含む引数の受け渡しが出来れば完全。

【追記おわり】



長くなった。findコマンドによる連番一括移動は次の機会に。

以上です。