Bash:ファイル名に各生年月日ごとにn個のファイルをコピーします。

Bash:ファイル名に各生年月日ごとにn個のファイルをコピーします。

ファイル名に生年月日を含む写真が数千枚あります。各出生年ごとに少なくとも100個のファイルを見つけてコピーする必要があります。たとえば、2000年生まれのための100ファイル、2001年生まれのための100ファイル...などがあります。

ファイル名の形式は次のとおりです。

35077502_1995-02-01_2012.jpg

この写真は2012年に撮影されたと推定されています。

bashスクリプトを使用して実行できますか?

ありがとう

答え1

#!/bin/bash

IFS=$'\n' years=( $(find . -maxdepth 1 -name '*.jpg' -print0 | 
                    sed -zEn 's/^.*_([0-9][0-9][0-9][0-9])-.*\.jpg/\1/p' | 
                    tr '\0' '\n' | 
                    sort -u)
                )

for year in "${years[@]}" ; do
  mkdir -p "$year"
  find . -iname "*_${year}-*.jpg" -size +1k -print0 |
    head -z -n 100 |
    xargs -0r cp -t "$year"
done

これは、現在のディレクトリのファイル名から抽出された一意の4桁の年のセットを含む配列($years)を構成します。ここで、年の前には下線(_)があり、その後にはダッシュ(-)が続きます。これにはsedakaオプションのGNUバージョンが必要です。-z--null-data

各年に対して最初にその年のディレクトリを作成し(ディレクトリがまだ存在しない場合)、それを使用してfind必要なパターンと一致し、1 KBを超えるすべてのファイル名を一覧表示します。次に、そのリストから最初の100行をインポートし、headファイルxargsを適切なディレクトリにコピーします。

ファイル名のリストは、すべての有効なファイル名に対して機能するようにパイプ全体でNULで終了します(つまり、ファイル名にスペース、タブ、改行文字、または他の珍しいが完全に有効な文字が含まれていても中断されません)。

これも必要ですGNUバージョンhead-z(これはLinuxの標準です。)オプション(  --zero-terminatedNUL終了入力とも呼ばれます)を使用するためです。特にバージョンが必要です。2016年1月13日更新。また、cpターゲットディレクトリが最後の引数ではなく最初の引数になることを可能にするGNU(別名)オプションも必要です。-t--target-directory

ファイルをソートする必要がある場合とsort -zコマンドの間に挿入できます。たとえば、GNUバージョンの 。findheadfind ... -print0 | sort -z ... | head -z ...sort

これは、あなたの質問のリビジョンに示されているように、ファイル名にアンダースコアがあり、.jpg拡張子の前の最後の項目に年が続くと仮定します。

-iname "*${year}*.jpg"年がファイル名のどこにでも表示される場合(下線なし、および間に秒を挿入)を使用できますが、*最初の8桁は部分文字列を含むファイルの数に似ていることに注意してください。${year}.jpg604200172001

また、すべてのファイルに、、、、などの代わりに(大文字と小文字を区別しない)拡張子があると仮定します.jpg。複数のファイル拡張子が必要な場合は、代わりにこのオプションを使用できます。.jpeg.jpe.jfif.gif.png-iregex-iname

答え2

ファイル名に不快な内容がなければできます

for year in 2000 2001; do
  cp `ls *${year}*.jpg|head -n 100` destination
done

答え3

そしてzsh

for y ({1995..2017}) (cp -- **/*_$y.jpg(.LK+1[1,100]) destination)
  • **/: すべてのレベルのサブディレクトリ内でアルファベット順にソート
  • .:一般ファイルのみ
  • LK+1:長さが1KiBを超えています。
  • [1,100]:最初の100個。

n(ソート順によってコピーするファイルが決まるため、数値でソートするにはglob修飾子を追加する必要があります。)

または、年のリストをハードコーディングし、ディレクトリを複数回クロールしないでください。

typeset -A files n
for f (**/*_<->.jpg(.LK+1)) {
  y=${${f##*_}%.*}
  ((++n[$y] > 100)) || files[$y]+=$f$'\0'
}
for y (${(k)files}) {
  mkdir -p $y && cp -- ${(0)files[$y]} $y
}

(テストされていません)

関連情報