ファイル名の最後に日付が変更されたタイムスタンプを持つファイルの名前を変更しますか?


14

たとえば、2012年6月20日にg.txtが最後に変更されたg.txtのような多数のファイルがあるディレクトリがあるとします。

2012年6月20日の最終変更日を最後に追加して、すべてのファイル(g.txtなど)のバッチ名を変更するにはどうすればよいですか?

回答:


13

現在のディレクトリ内のすべての(グロビング)ファイルの名前を変更するにはクイックと汚いバッシュワンライナーfilename.txtfilename.txt-20120620

for f in *; do mv -- "$f" "$f-$(stat -c %Y "$f" | date +%Y%m%d)"; done

進取の気性のあるBashオタクは、それを打破するためのエッジケースを見つけるでしょう。:)

明らかに、これはファイルの最後に日付のようなものが既にあるかどうかをチェックするなどの望ましいことを行いません。


2
+1、よさそうだ。mvの最初の引数として「-」を使用することで、もう少し堅牢にすることができます。'-'で始まるファイルに対する保護
cas

5
それはどのようなdate実装ですか?私のGNU dateは入力を処理していないようです。
マナトワーク

RHEL 6のcoreutils 8.4
jgoldschrafe

2
@jgoldschrafe、コードが適切に機能することを確認してください。pastebin.com/nNYubf3A
manatwork

5
良いキャッチマナトワーク。GNU date 8.13もstdinからの読み取りをサポートしていません。"date" +%Y%m%d -r $ f "-r"を含むファイルのmod timeの使用をサポートしているため、この特定のケースではstatは必要ありません。
cas

18

以下は、goldschrafeのワンライナーのバージョンです。

  • statを使用しません
  • GNU dateの以前のバージョンで動作します
  • ファイル名のスペースを正しく処理します
  • ダッシュで始まるファイル名にも対応しています

    for f in *; do mv -- "$f" "$f-$(date -r "$f" +%Y%m%d)"; done


1
あなたはそれを作る必要があるdate -r "$f" +%Y%m%dかどうかは動作しませんPOSIXLY_CORRECT環境にあります。一般的に、オプションは他の引数の前に配置する必要があります。
ステファンシャゼラス

これは「正解」である必要があります
-invalidusername

もちろん、中括弧は必要ありません"${f}"
G-Manが「Reinstate Monica」と言う

しかし、たとえば「Ymd-filename」などのように前置する日付をどのようにするのでしょうか?
timebandit

2

必須の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}'

1

私が理解したように、私たちは修正日が何であるかを事前に知りません。そのため、各ファイルから取得し、出力をフォーマットし、ファイル名に変更日が含まれるように各ファイルの名前を変更する必要があります。

このスクリプトを「modif_date.sh」のような名前で保存し、実行可能にすることができます。ターゲットディレクトリを引数として呼び出します。

modif_date.sh txt_collection

「txt_collection」は、名前を変更するすべてのファイルがあるディレクトリの名前です。

#!/bin/sh

# Override any locale setting to get known month names
export LC_ALL=c
# First we check for the argument
if [ -z "$1" ]; then
    echo "Usage: $0 directory"
    exit 1
fi

# Here we check if the argument is an absolute or relative path. It works both ways
case "${1}" in
  /*) work_dir=${1};;
  *) work_dir=${PWD}/${1};;
esac

# We need a for loop to treat file by file inside our target directory
for i in *; do
    # If the modification date is in the same year, "ls -l" shows us the timestamp.
    # So in this case we use our current year. 
    test_year=`ls -Ggl "${work_dir}/${i}" | awk '{ print $6 }'`
    case ${test_year} in *:*) 
        modif_year=`date '+%Y'`
        ;;
    *)
        modif_year=${test_year}
        ;;
    esac
    # The month output from "ls -l" is in short names. We convert it to numbers.
    name_month=`ls -Ggl "${work_dir}/${i}" | awk '{ print $4 }'`
    case ${name_month} in
            Jan) num_month=01 ;;
            Feb) num_month=02 ;;
        Mar) num_month=03 ;;
        Apr) num_month=04 ;;
        May) num_month=05 ;;
        Jun) num_month=06 ;;
        Jul) num_month=07 ;;
        Aug) num_month=08 ;;
        Sep) num_month=09 ;;
        Oct) num_month=10 ;;
        Nov) num_month=11 ;;
        Dec) num_month=12 ;;
        *) echo "ERROR!"; exit 1 ;;
    esac
    # Here is the date we will use for each file
    modif_date=`ls -Ggl "${work_dir}/${i}" | awk '{ print $5 }'`${num_month}${modif_year}
    # And finally, here we actually rename each file to include
    # the last modification date as part of the filename.
    mv "${work_dir}/${i}" "${work_dir}/${i}-${modif_date}"
done

1
stat(1)のmanページを読んで、スクリプトを約3/4に縮小する方法を見つけてください。上記のほとんどは、車輪の再発明です。特に、 'stat -c%Y'は、エポック(1970-01-01 00:00:00)以降の秒単位でファイルの変更時間を示します。これをdate(1)への入力として使用して、必要に応じてタイムスタンプをフォーマットできます。例については、上記のjgoldschrafeの回答を参照してください。
cas

@CraigSanders利点は、このスクリプトがLinux以外のオペレーティングシステムで動作することです。Linuxには、異なるstatユーティリティがあるか、まったくありません。
ジル 'SO-悪であるのをやめる

の出力の解析はls信頼できないことに注意してください。一部のUNIXバリアントでは、ユーザー名とグループ名にスペースを含めることができます。これにより、日付列の位置合わせが無効になります。
ジル「SO-悪であるのをやめる」

@giles:本当ですが、賢明な人は誰でも:-) Linux以外のシステムにGNU coreutils(および他のすべてのGNUツール)をインストールします。これは、ユーザーランドツールの優れたセットだけでなく、基盤となるカーネルに関係なく一貫したセットを取得する最も簡単な方法です。
cas

1
(続き)…(5)別のバグ:日付と時刻(日付と年ではなく)ls として表示される日付/時刻は、現在の年でなければならないことを前提としています。本当じゃない。過去6か月間です。それは前年にある可能性があります(たとえば、2016年9月27日から2016年12月31日までは過去6か月以内です)。(6)GregのWiki(すでに@Gillesが引用している)をオウムする危険があるため、改行とスペースを含むファイル名はこれを失敗させる可能性があります。…(続き)
G-Manが「Reinstate Monica」と言う

0

casのone-linerのバージョン(goldschrafeのonelinerに基づく)は、べき等性で拡張されています。

すなわち、日付時刻でファイルに接頭語をつけて、日付時刻接頭語をまだ持っていないものだけのためにこれをするために拡張されました。

ユースケース:ディレクトリに新しいファイルを追加し、まだ存在していないファイルに日時のプレフィックスを追加する場合に役立ちます。

for f in * ; do
  if [[ "$f" != ????-??-??' '??:??:??' - '* ]]; then
    mv -v -- "$f" "$(date -r "$f" +%Y-%m-%d' '%H:%M:%S) - $f" ;
  fi;
done

あなたのファイルのタイムスタンプをねじ込んでJPEGファイルされている場合は、もみは、EXIFデータとそれらを修正することもできます。for f in *.jpg ; do jhead -ft "$f" ; doneソース:unix.stackexchange.com/a/290755/9689
グジェゴシWierzowiecki
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.