
たとえば、g.txt のようなファイルが多数含まれるディレクトリがあり、g.txt が最後に変更されたのは、たとえば 2012 年 6 月 20 日だとします。
すべてのファイル (g.txt など) の名前を一括変更して、末尾に最終更新日 2012 年 6 月 20 日を追加するにはどうすればよいでしょうか。
答え1
以下はゴールドシュラーフェのワンライナーのバージョンです:
統計を使用しない
GNU dateの以前のバージョンで動作します
ファイル名内のスペースを正しく処理します
ダッシュで始まるファイル名にも対応
for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done
2021-03-20更新
この質問に対する私の回答は何年も私を悩ませてきました (まあ、私がそれを思い出したときだけ - 今日のようにまた賛成票が入ったときだけ) ので、ついに更新します。上記の私の元の回答はまだ有効ですが、以下の更新された回答の方が優れています。
のようにどれでもバッチファイルの名前変更操作は、パール rename
ユーティリティであり、扱いにくいシェルの for ループではありません。
perl 名前変更ユーティリティは、実質的には、単純な正規表現操作 (ほとんどの名前変更タスクに十分) から複雑な複数行のスクリプトまで、任意の perl コードを使用してファイルの名前を変更できる特殊なs/search/replace/
スクリプト言語です。
例えば
rename -n 'BEGIN {use Date::Format};
die $! unless -f $_;
next if (m/-\d{8}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/$/-$dt/;' *.txt
これにはperlとモジュールだけが必要ですDate::Format
(このモジュールは非常に便利なので、perlがインストールされているシステムならどこにでもインストールしておくべきです。私の意見では、作者のGraham Barrのモジュールと一緒にDate::Parse
、すべきcpan
これは Perl のコア モジュール ライブラリの一部ですが、そうではないため、または Debian のパッケージのようなディストリビューション パッケージを使用してインストールする必要がありますlibtimedate-perl
。
ちなみに、このスクリプトは、ファイル名の末尾に日付 (つまり 8 桁) が既に含まれているように見えるファイルをスキップします。
または、ファイルのサフィックス(ある場合)の前に日付を置く、より洗練されたバージョンの場合:
rename -n 'BEGIN {use Date::Format; use File::Basename};
die $! unless -f $_;
my ($filename,$dirs,$suffix) = fileparse($_,qr/\.[^.]*/);
next if (m/-\d{8}${suffix}$/);
my $ts=(stat($_))[9];
my $dt=time2str("%Y%m%d",$ts);
s/${suffix}$/-${dt}${suffix}/;' *.txt
このバージョンには追加の要件はありません。これはFile::Basename
、私が覚えている限り (少なくとも 10 年以上、おそらくそれ以上)、このモジュールが Perl の標準コア モジュールとして含まれていたためです。
注記:上記の両方のrename
スクリプトは、rename の-n
(別名--nono
)「dry-run」オプションを使用しているため、結果を適用する前にテスト/シミュレートできます。が目的どおりに機能することが確実になったら、 を削除します (または、詳細な出力の場合は に-n
置き換えます)。-v
また、次の点にも注意してください:他の Perl スクリプトと同様にrename
、コマンドラインや標準入力から指定されたファイル名を変更できます。たとえば、現在のディレクトリとすべてのサブディレクトリにあるすべての .txt ファイルの名前を変更するには、次のようにします。
find . -type f -iname '*.txt' -print0 |
rename -0 --nofullpath -n '..........'
rename
ところで、ここではの --nofullpath (別名-d
、--filenmame
、 ) オプションを使用して--nopath
、見つかったファイルパスのファイル名部分のみの名前を変更するようにしています。この特定のケースでは必要ありません (サンプルの名前変更スクリプトはファイル名の末尾のみを変更するため) が、ファイル名だけでなくパスも名前変更したくない場合は、一般的にこのオプションを使用することをお勧めします (たとえば、's/ //g'
ファイル名からスペースを削除するような名前変更スクリプトは、 のないファイル名だけでなくパスのスペースも削除しようとするため--nofullpath
、おそらくエラーが発生して失敗します)。
ついに:perl の名前変更スクリプト (別名File::Rename
、またはprename
Fedora と RedHat では 、または と呼ばれることもありますperl-rename
) を、rename と呼ばれる他のプログラムと混同しないでください。 のみこの Perl ベースの名前変更ユーティリティは、上記のように任意の Perl コードを使用してファイルの名前を変更できますが、他の名前変更ユーティリティには異なる機能と異なる互換性のないコマンドライン オプションがあります。
正しい名前変更がインストールされているかどうかを確認できます:
$ rename -V
/usr/bin/rename using File::Rename version 1.13, File::Rename::Options version 1.10
実行可能ファイルはシステムによってprename
またはperl-rename
または と呼ばれる場合があります。これらを試し、正しい実行可能ファイル名を使用するように上記の例を調整してください。file-rename
-V
答え2
filename.txt
現在のディレクトリ内のすべての(glob)ファイルの名前を からに変更する、手っ取り早い Bash ワンライナーfilename.txt-20120620
:
for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done
進取の気性に富んだ Bash オタクなら、きっとそれを破るエッジケースを見つけるでしょう。:)
明らかに、これは、ファイルの末尾に日付のようなものがすでにあるかどうかを確認するなどの望ましい処理は実行しません。
答え3
必須の zsh ワンライナー (オプション コンポーネントの 1 回限りの読み込みは除く):
zmodload zsh/stat
autoload -U zmv
zmv -n '(*)' '$1-$(stat -F %Y%m%d +mtime -- $1)'
組み込み関数stat
をzsh/stat
モジュール、 そしてそのzmv
ファイル名を変更する関数。また、拡張子がある場合は、拡張子の前に日付を配置する追加機能もあります。
zmv -n '(*)' '$1:r-$(stat -F %Y%m%d +mtime -- $1)${${1:e}:+.$1:e}'
答え4
これはcasのワンライナーのバージョンです(goldschrafeのワンライナーに基づいており、次のように拡張されています)。冪等性、
つまり、ファイルの先頭に日付と時刻を付けるようになり、日付と時刻のプレフィックスがまだない場合にのみこれを実行します。
使用例: ディレクトリに新しいファイルを追加し、まだプレフィックスが付いていないファイルに日付と時刻のプレフィックスを追加する場合に役立ちます。
for f in * ; do
if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
fi;
done