ファイルを作成し、ファイル名の日付と時刻に基づいてフォルダーにソートします。

ファイルを作成し、ファイル名の日付と時刻に基づいてフォルダーにソートします。

Main私のフォルダには、次のような名前のファイルがたくさんあります。

2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz
2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz  2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz
2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz  2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz
2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz  2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz
2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz  2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz
2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz

最初の10文字は日付を表し、その後に数字(24時間形式の時間)が表示されます。残りは無視できるファイルの詳細です。

Mainファイル名の日付に基づいてそのフォルダ内にフォルダを作成し、ファイル名の時刻に基づいて日付フォルダ内に別のフォルダを作成したいと思います。最終的にMainフォルダ内のファイルをその時間フォルダに移動したいと思います。

Main -> Date -> hh -> file.csv.gz

たとえば、フォルダ内2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gzのファイルは、Main次のパスを持つこのようなフォルダに保存されます。Main/2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz

上記のように、フォルダ内のファイルをグループ化するためにbashスクリプトを使用するのに役立ちますか?

答え1

このperl renameユーティリティを使用してください。

file-rename注:Perlの名前変更は、、、またはとも呼ばれperl-renameますprename。機能とコマンドラインオプションが完全に異なり、互換性のないrenameユーティリティと混同しないでください。util-linuxperl renameはDebian ... IIRCのデフォルトの名前変更で、prenameCentosのパッケージにあり、コマンドprenamerename

$ rename -n 'if (m/(^\d{4}_\d\d_\d\d)_(\d\d)/) {
               my ($date,$hour) = ($1,$2);
               my $dir = "./$date/$hour/";
               mkdir $date;
               mkdir $dir;
               s=^=$dir=
             }' *
rename(2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz, ./2021_10_15/23/2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz)
rename(2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz, ./2021_11_24/21/2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz)
rename(2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz, ./2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz)
rename(2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz, ./2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz)
rename(2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz, ./2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz)
rename(2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz, ./2021_11_24/21/2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz)
rename(2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz, ./2021_11_25/20/2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz)
rename(2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz, ./2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz)
rename(2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz, ./2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz)
rename(2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz, ./2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz)

これは-nテスト実行オプションで実際に実行するのではなく、実行するアクションのみを表示します。-v名前変更スクリプトが目的の操作を実行すると確信している場合は、そのスクリプトを削除してください(または詳細な出力に置き換えてください)。

スクリプトは最初に抽出して機能します。日付そして時間各ファイル名の一部(一致しないファイル名をスキップ)してディレクトリを作成し、ファイル名をdateそのdate/hourディレクトリに変更します。

これは、ファイル名が現在のディレクトリにあると仮定します。それ以外の場合は、m//最初の行で一致する正規表現を調整する必要があります。そしてs===2行目の代替正規表現です。


使用された代替バージョンファイルパスperlコアモジュール(perlに含まれる)を2回使用する代わりにmkdir(関数はシェルコマンドmake_pathのように動作します):mkdir -p

$ rename -v 'BEGIN {use File::Path qw(make_path)};
             if (m/(^\d{4}_\d\d_\d\d)_(\d\d)/) {
               my $dir = "./$1/$2/";
               make_path $dir;
               s=^=$dir=
             }' *
2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz renamed as ./2021_10_15/23/2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz
2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz renamed as ./2021_11_24/21/2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz
2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz renamed as ./2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz
2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz renamed as ./2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz
2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz renamed as ./2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz
2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz renamed as ./2021_11_24/21/2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz
2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz renamed as ./2021_11_25/20/2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz
2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz renamed as ./2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz
2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz renamed as ./2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz
2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz renamed as ./2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz

これは、最初のバージョンより実際には優れていませんが、Perlコード、Perlモジュールを使用してファイルの名前を変更したりファイルを移動したりすることができます。


3番目のバージョンは次のものを使用します。ファイル::デフォルト名入力パス名を$pathおよび$file部分に分割します。現在のディレクトリまたは別のディレクトリのファイル名を処理できます。 File::BasenameこれはコアPerlモジュールなので、Perlに含まれています。これは3つの便利な機能を提供しますbasename()dirname()同じ名前のシェルツールと同様に機能します)、fileparse()これはデフォルトの名前とディレクトリを別々の変数に抽出するためにこのスクリプトで使用されます。

rename -n 'BEGIN {use File::Path qw(make_path); use File::Basename};
           my ($file, $path) = fileparse($_);
           if ($file =~ m/(\d{4}_\d\d_\d\d)_(\d\d)/) {
             my $dir = "$path/$1/$2";
             make_path $dir;
             $_ = "$dir/$file"
           }' /home/cas/rename-test/*
rename(/home/cas/rename-test/2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz, /home/cas/rename-test/2021_10_15/23/2021_10_15_23_35_SIP_CDR_pid3894_ins2_thread_1_4718.csv.gz)
rename(/home/cas/rename-test/2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz, /home/cas/rename-test/2021_11_24/21/2021_11_24_21_15_Gi_pid25961_ins2_thread_1_6438.csv.gz)
rename(/home/cas/rename-test/2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz, /home/cas/rename-test/2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins2_thread_1_6485.csv.gz)
rename(/home/cas/rename-test/2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz, /home/cas/rename-test/2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins3_thread_2_6485.csv.gz)
rename(/home/cas/rename-test/2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz, /home/cas/rename-test/2021_11_24/21/2021_11_24_21_15_Gi_pid27095_ins4_thread_3_6485.csv.gz)
rename(/home/cas/rename-test/2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz, /home/cas/rename-test/2021_11_24/21/2021_11_24_21_15_Gi_pid681_ins5_thread_4_6457.csv.gz)
rename(/home/cas/rename-test/2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz, /home/cas/rename-test/2021_11_25/20/2021_11_25_20_55_Gi_pid29741_ins5_thread_4_7540.csv.gz)
rename(/home/cas/rename-test/2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz, /home/cas/rename-test/2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins3_thread_2_7489.csv.gz)
rename(/home/cas/rename-test/2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz, /home/cas/rename-test/2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins4_thread_3_7488.csv.gz)
rename(/home/cas/rename-test/2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz, /home/cas/rename-test/2021_11_25/20/2021_11_25_20_55_Gi_pid30842_ins5_thread_4_7489.csv.gz)

しかし、ファイルを完全に別のパスに移動するように変更するのは簡単ではありません。次my $dir = "/my/new/path/$1/$2";のようにしてください。my $dir = "$path/$1/$2";

鍵は方法を理解することです。真珠 renameユーティリティは次のように動作します。そして、もし名前変更スクリプトは、$_変数を変更した後にファイル名を新しい値に変更しようとします$_。変更されていない場合、$_名前の変更は試行されません。そのため、以下を使用できます。どのファイル名を変更するPerlコード - あなたがしなければならないことは$_ほとんど非常に簡単なsed名前変更スクリプト(rename 's/ +/_/g' *ファイル名のスペース名を下線付き)を使用しますが、名前変更アルゴリズムは必要に応じてカスタマイズできます。そして複雑さ。

$_Perlでは非常に重要な変数です。ファイルハンドルとループイテレータの入力を保持するデフォルト変数として使用されます。プログラマが指定しない場合m//、、s///など、複数の演算子tr///の基本オペランドとしても使用されます。たくさん(すべてではない)機能。表示man perlvarと検索$_(less asからエスケープする必要があります\$_


ちなみに、以前に言及していないことの1つは、renameコマンドラインまたは標準入力でファイル名を引数として使用できることです。デフォルトは標準入力から改行で区切られた入力です(したがって、改行を含むファイル名では機能しません。迷惑ですが完全に有効な可能性です)。-0引数を使用して、改行区切りの代わりにNUL区切り入力を使用することができます。したがって、NULで区切られたファイル名のリストを生成できる任意の入力から入力を取得するすべてのファイル名を使用できます(たとえば、find ... -print0しかしより良い場合があります。findオプションのみを使用するには-exec ... {} +)。

rename-fまたは、オプションを使用しないと、既存のファイルのファイル名の変更も拒否されます--force

答え2

代わりにディレクトリで使用するには、次の手順を実行zshします。bashMain

zmodload zsh/files # to get builtin mkdir/mv to speed things up

mkdmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -n -P mkdmv '(<->_<->_<->)_(<->)_*.csv' '$1/$2/$f'

-n(満足したらテスト実行を削除します)。

zmv衝突が発生したときにデータが失われないようにするために、タスクを実行する前に完全性チェックが実行されます。これは、他のほとんどの一括名前変更ユーティリティと比較して利点の1つです。

<->すべてのASCII数値シーケンスと一致します。より具体的な一致が必要な場合は、これを行うことが(<1970-2099>_<1-12>_<1-31>)_(<0-23>)_*.csvできます。

関連情報