ディレクトリ名の末尾の年を前に移動します。 YYYY-MM-DD形式に変換できます。

ディレクトリ名の末尾の年を前に移動します。 YYYY-MM-DD形式に変換できます。

MacからPCにすべての写真をエクスポートしました(Windows 11、PowerShellでUbuntuを実行)。エクスポートは元の作成日を削除し、フォーマットで各ディレクトリ(何千ものフォルダ)を作成しました。

April 1, 2004         
Amsterdam, September 18, 2018    
Anderson Arbor, March 24, 2011   

日付で並べ替えたいです。これらの形式を次のように変更する方法についてのアイデアはありますか?

2004, April 1   
2018, Amsterdam, September 18    
2011, Anderson Arbor, March 24

または、より良い方法は次のとおりです。

2004-04-01    
2018-09-18 Amsterdam     
2011-03-24 Anderson Arbor

答え1

そしてzsh

$ autoload -Uz zmv
$ zmodload zsh/datetime
$ zmv -n '(|(*), )([^ ]## <1-31>, <->)' \
         '$(strftime %F $(strftime -r "%B %d, %Y" $3))${2:+ $2}'
mv -- 'Amsterdam, September 18, 2018' '2018-09-18 Amsterdam'
mv -- 'Anderson Arbor, March 24, 2011' '2011-03-24 Anderson Arbor'
mv -- 'April 1, 2004' 2004-04-01

-n満足すれば削除(テスト実行))。

zmvバッチ名を変更するための自動ロード可能なzsh関数。

2つのパラメータが必要です。

  1. グローバルモード(拡張はそれ自体で行われるため、引用符で囲む必要がありますzmv)。
  2. 一致する各ファイルを置き換えるために文字列が評価されます。

置換で一致する各ペアは、...(...)にあります。$1$2

ここで、グローバルパターンは(|(*), )([^ ]## <1-31>, <->)次のとおりです。

  • (x|y)またはに一致するので、x何でもy一致する(|(*), )か(2番目のペアにあるため、代替項目で*終わる)で終了します。$2(...)", "
  • [^ ]x##1つ以上のxsと一致するスペースを除くすべての単一文字と一致するため、スペースではなく[^ ]##1つ以上の文字で構成されるすべてのシーケンスと一致します。
  • <->、境界なしの<x-y>すべての数字と一連の10進数と一致します。

代替では、モジュールstrftimeに組み込まれている関数を使用してからキャプチャされた日付をzsh/datetime解析(消費)し、フォーマットを再指定します。この組み込み機能はシンプルな標準インターフェースを提供し、それぞれフォーマットとアス機能を提供します。-r$3strftime()strptime()fptimestr

%F%Y-%m-%d日付形式を YYYY-MM-DD で表示する略語で、%B完全月名、%d特定の日付、%Y年を表します。


コマンドの置き換えに使用する代わりに、langinfoから月名のリストを取得してから手動で月番号と形式に変換できます。strftimeこれは、出力を得るために毎回プロセスをフォークすることを意味します。

zmodload zsh/langinfo
autoload -Uz zmv
months=( ${(v)langinfo[(I)MON_<1-12>]} )
#       1 2     3                 4         5
zmv -n "(|(*), )(${(j[|])months}) (<1-31>), (<->)" \
       '$5-${(l[2][0])months[(I)$3]}-${(l[2][0])4}${2:+ $2}'

どこ:

  • ${(v)langinfo[(I)MON_<1-12>]}キーが一致する連想配列の値に展開されますv$langinfoMON_<1-12>
  • ${(j[|])months} joins 配列の要素です|
  • $array[(I)$3]に格納されているパターンに一致する配列要素の最大インデックスを返します$3
  • ${(l[2][0])string} l2eftはsで文字列の長さを埋めます0

答え2

findPerlrenameユーティリティ(使用しているディストリビューションに応じてともprename呼ばれる)を使用し、file-renameperl-rename日付::分析そして日付形式ライブラリモジュール。

これらのモジュールはPerlには含まれていないため、個別にインストールするか、Perlを介してインストールする必要があります。ファンコマンドラインツールまたは配布パッケージ。みんなここにいます。時間の日付Debian では .bundle からインストールできますsudo apt-get install libtimedate-perl。他のディストリビューションでは、このパッケージの名前が何であるかわかりませんが、おそらく非常によく似ています。

ただし、Perlユーティリティとはまったく異なる互換性のない機能とコマンドラインオプションを持つユーティリティを混同しないでくださいrenamerenameutil-linux

それでも:

$ mkdir 'April 1, 2004' 'Amsterdam, September 18, 2018' 'Anderson Arbor, March 24, 2011'

$ find . -type d -print0 |
  rename -n -0 'BEGIN {
                  use Date::Parse;
                  use Date::Format;
                  our $date_pattern = qr/[[:alpha:]]+ \d+, \d\d\d\d/;
                };
                our $date_pattern;

                if (/^(.*\/)(.*)\b($date_pattern)$/) {
                  my ($p1, $p2, $d) = ($1, $2, $3);
                  my $t = str2time($d);

                  s/\b$date_pattern//;
                  $_ = sprintf("%s%s%s", $p1, time2str("%Y-%m-%d ",$t), $p2);
                  s/[, ]*$//;
                }'
rename(./April 1, 2004, ./2004-04-01)
rename(./Amsterdam, September 18, 2018, ./2018-09-18 Amsterdam)
rename(./Anderson Arbor, March 24, 2011, ./2011-03-24 Anderson Arbor)

注:-nこれはこのオプションによるテスト実行です。必要に応じて動作することを確認したら、-nそれを削除するか、-v詳細な出力に置き換えてください。

Date::Parse および Date::Format モジュールをロードし、$date_patternブロック ( ) に変数を定義した後、BEGIN {}この名前変更スクリプトは各ディレクトリ名を繰り返し、「月、年」パターンを一致させようとします。

成功すると、パス名の最後の要素を除くすべての要素が変数としてキャプチャ/抽出され、$p1日付パターンの前にある最後のディレクトリ要素の「プレフィックス」部分が変数に入ります$p2(これはオプションであり、欠落している場合は空の文字列です)。変数に入れます$d

その後、一致する日付は値(1970年1月1日午前0時から秒)$dに変換され、この関数を使用して変数に割り当てられます。time_t$tstr2time()

それから:

  1. ディレクトリ名から日付パターンが削除されました。

  2. sprintfおよび関数は、をtime2str()変更してファイル名全体を新しいパターンに合わせて変更するために使用されます$_

    この単純な割り当ては、$_Perlがどのように機能するかについて非常にシンプルで重要な事実を強調しますrename

    Perlで他の変数名(参照と検索)が指定されていない場合(演算子を含む)、その変数は$_ループのデフォルト変数として使用され、多くの関数と演算子のデフォルトの引数/オペランドとして使用されます。man perlvar$_s///

    Perlの名前変更の場合、$_現在のパス/ファイルの名前を変更すると$_名前が変更されます。変更すると$_名前も変更されます。変わらないといけません。

    気づくrename に慣れる-fこのオプションを使用して、この操作を強制的に適用しない限り、既存のファイル名を上書きするようにファイルまたはディレクトリの名前を変更します。

  3. 次に、最後のディレクトリ名からすべての末尾のスペースとカンマ(存在する場合)を削除します。


その他の注意事項:

  1. 変数は、スクリプトの起動時に一度だけ実行されるように$date_patternブロックに定義されています(stdinの各ディレクトリ名に対して1回ではありません)。BEGIN{}2回使用されるため、変数として定義されます。変更する必要がある場合は、1つの場所でのみ変更することをお勧めします。 「1つ以上の英字、1つのスペース、1つ以上の数字、1つ以上のスペース、4つの数字」と定義されます。これは、サンプルのディレクトリ名と一致しますが、他のバリエーションが可能な場合は調整する必要があります。

    名前変更スクリプトの全範囲内で使用できるように宣言されますour(そうでない場合は、BEGINブロック内でのみ使用可能)。 Perlの名前変更スクリプトはstrictPerlモードで実行されます(perldoc strict詳細情報を参照)。

    qr正規表現を引用する(おそらくパフォーマンスを向上させるためにプリコンパイルする)Perl引用演算子です。ここでのパフォーマンスはおそらく問題ではないでしょう。ここでは、主に一重引用符を使用することが1行以内で痛いという事実を解決するために使用しています。スクリプト。perldoc -f qr詳細より。

  2. find ... -print0andオプションrenameを使用すると、NULはファイル名の区切り文字として使用されるため、これはすべてのディレクトリ名、-0改行、その他のスペースまたはシェルメタ文字(など)を含む;ディレクトリ名にも適用されます&。 NUL>ただパス名に現れない文字です。

答え3

使用真珠rename:

Time::PiecePerlの中心に位置し、100%信頼できるDate::Parseモジュールではなく、「魔法」よりもきちんとした方法と見なされます。

rename -n '
    BEGIN{use Time::Piece}
    my $d = localtime;
    my $months_re = join "|", map { "$_\\w+" } $d->mon_list;
    s/
        ($months_re)
        \s+(\d+),\s+(\d{4})
    /
        my $d = Time::Piece->strptime("$1 $2, $3", "%B %d, %Y");
        $d->strftime("%F")
    /xe;
    s/(.*),\s+(\d{4}-\d{2}-\d{2})/$2 $1/;
' ./*/

出力がうまくいったら削除してください-n(別名)。dry-run

出力

rename(Amsterdam, September 18, 2018/, 2018-09-18 Amsterdam/)
rename(Anderson Arbor, March 24, 2011/, 2011-03-24 Anderson Arbor/)
rename(April 1, 2004/, 2004-04-01/)

関連情報