シェルで複数の(複合を含む)拡張子を使用してファイルセットの名前を変更する

シェルで複数の(複合を含む)拡張子を使用してファイルセットの名前を変更する

拡張子はたくさんありますが、名前には一意のファイルセットのリストがあります。

filename-1.foo.001
...
filename-1.foo.020
filename-1.foo.baz
filename-1.foo.bar1-2.baz
...
filename-1.foo.bar7-8.baz

another_filename.foo.001
another_filename.foo.002
...
another_filename.foo.009
another_filename.foo.baz
another_filename.foo.bar1-2.baz
another_filename.foo.bar3-4.baz
another_filename.foo.bar4-5.baz
another_filename.foo.bar7-8.baz

yet.a.different.file.name.foo.001
yet.a.different.file.name.foo.002
...
yet.a.different.file.name.foo.287
yet.a.different.file.name.foo.baz
yet.a.different.file.name.foo.bar1-2.baz
yet.a.different.file.name.foo.bar3-4.baz
yet.a.different.file.name.foo.bar4-5.baz
yet.a.different.file.name.foo.bar7-8.baz

moreFileNaming.foo.001
...
moreFileNaming.foo.009
moreFileNaming.foo.baz
moreFileNaming.foo.bar1-2.baz
moreFileNaming.foo.bar3-4.baz
moreFileNaming.foo.bar4-5.baz
moreFileNaming.foo.bar7-8.baz

各グループのランダムなファイル名を取得するために名前を変更するために使用する出力はopenssl rand -hex 8次のとおりです。

9874f7187c914ea9.foo.001
...
9874f7187c914ea9.foo.020
9874f7187c914ea9.foo.baz
9874f7187c914ea9.foo.bar1-2.baz
...
9874f7187c914ea9.foo.bar7-8.baz

2f54a0b6528e3927.foo.001
2f54a0b6528e3927.foo.002
...
2f54a0b6528e3927.foo.009
2f54a0b6528e3927.foo.baz
2f54a0b6528e3927.foo.bar1-2.baz
2f54a0b6528e3927.foo.bar3-4.baz
2f54a0b6528e3927.foo.bar4-5.baz
2f54a0b6528e3927.foo.bar7-8.baz

71ad0aa90148b2f5.foo.001
71ad0aa90148b2f5.foo.002
...
71ad0aa90148b2f5.foo.287
71ad0aa90148b2f5.foo.baz
71ad0aa90148b2f5.foo.bar1-2.baz
71ad0aa90148b2f5.foo.bar3-4.baz
71ad0aa90148b2f5.foo.bar4-5.baz
71ad0aa90148b2f5.foo.bar7-8.baz

3721323156e921b5.foo.001
...
3721323156e921b5.foo.009
3721323156e921b5.foo.baz
3721323156e921b5.foo.bar1-2.baz
3721323156e921b5.foo.bar3-4.baz
3721323156e921b5.foo.bar4-5.baz
3721323156e921b5.foo.bar7-8.baz

私は試しましたがfor name (*.(<->|baz|bar<->.baz) result=$(openssl rand -hex 16) && mv $name $result(これは以前に何度も繰り返したので動作しない可能性があります)、うまくいくとファイルごとランダム名、各グループが同じ名前、ランダム、および同じサイズを維持したいと思います。 Sha1sumや他の方法も動作します。

この目標をどのように達成できますか?特にファイルの場合.foo.bar-*.baz?

fooを削除すると

3721323156e921b5.001
...
3721323156e921b5.009
3721323156e921b5.baz
3721323156e921b5.bar1-2.baz
3721323156e921b5.bar3-4.baz
3721323156e921b5.bar4-5.baz
3721323156e921b5.bar7-8.baz

それも大丈夫でしょう。追加の質問:

  1. ファイルの先頭で.fooを見つける方法は?
  2. たとえば、生成された変数を繰り返してresult=$(openssl rand -hex 8)名前変更に使用でき、1セットが完了した場合にのみ、次のセットが完了するまで繰り返すように再割り当てできますか?

ありがとうございます!

ベストアンサー1

この質問にはいくつかの部分があります。

  1. 各ファイル名を基本部分と拡張子で除算します。
  2. 各名前の基本部分に一貫した変換を適用します。
  3. 拡張子を維持しながら、選択した基本部品変換に基づいてファイル名を変更します。

1. ファイル名の分解

ファイル名の必須部分が何であると思うかは、例の名前から完全には明確ではありません。区切り文字は明らかにポイントですが、この例ではyet.a.different.file.name.foo.bar1-2.bazどのような点ですか? tryの使用について言及しましたが、拡張として*.(<->|baz|bar<->.baz)扱われません。拡張として許可する1つの調整は 。その後、次のようにファイル名を混乱させることができます。foobar1-2.(foo|<->|baz|bar<->(|-<->).baz)$f

setopt extended_glob
base=${f%%(.(<->|baz|bar<->(|-<->).baz))#}; extensions=${f#$base}

あるいは、基本が最初の以前(および除く)のすべてとして定義できる場合、.foo.分解はより簡単になります。

base=${f%*.foo.*}; extensions=${f#$base}

2. 一貫した変換の適用

決定論的な変換を適用するには、毎回再計算するだけです。たとえば、キーを使用して名前のMACをインポートすると、疑似ランダムな結果が得られます(毎回同じキーを使用)。

secret=$(openssl rand -hex 32)
for … # Loop over the files as per (3.), set $base and $extensions as per (1.)
  new_base=${"$(openssl dgst -sha256 -hmac $secret <<<$base)"[-16,-1]}

ps(注:実行時に秘密鍵を実行すると、他のユーザーが秘密鍵を見ることができます。opensslあなたの場合、これは問題ではないと思いますが、将来の読者はこれを知る必要があります。)

ランダム変換を適用するには、各ベースが何にマップされているかを覚えておく必要があります。これを行う方法は2つあります。

  • ファイルをベースごとにグループ化し、一度に1つのベースとして処理できます。
  • ファイルを1つずつ処理できますが、各ベースが何にマップされているかを覚えていて、まだベースを表示していない場合にのみ新しいマッピングを作成してください。

2番目の方法は比較的簡単なので、最初の方法には特別な利点はありません。

設立する連想配列ベースを新しいベースにマッピングします。

typeset -A mapping
mapping=()
for … # Loop over the files as per (3.), set $base and $extensions as per (1.)
  if ((!$+mapping[$base])); then
    mapping[$base]=$(openssl rand -hex 8)
  fi
  new_base=$mapping[$base]

3. ファイル名の変更

Zshにはファイル名を変更するのに非常に便利なツールが用意されています。zmv。実行したい変換は複雑で、zmvはそれをマイナーにしません。ファイル名の分解と変換の両方に追加の作業が必要です。あなたの場合でもzmvにはいくつかの小さな利点があります。特に衝突が発生すると、zmvはエラーを発生させます(短い長さを使用しない限り、ランダムな要因によって発生する可能性はほとんどありません)。しかし、名前変換が難しいため、zmvを使用するのは厄介でシンプルなループを書くのが簡単です。

以下は、ランダムな名前を使用した完全なスニペットです。

setopt extended_glob
typeset -A mapping
mapping=()
for f in *.(foo|<->|baz|bar<->(|-<->).baz); do
  base=${f%%(.(foo|<->|baz|bar<->(|-<->).baz))#}; extensions=${f#$base}
  if ((!$+mapping[$base])); then
    mapping[$base]=$(openssl rand -hex 8)
  fi
  new_base=$mapping[$base]
  mv -i -- $f $new_base$extensions
done

これは、指定された値に対して決定的な名前を使用する完全なフラグメントです$secret

setopt extended_glob
secret=$(openssl rand -hex 32)
for f in *.(foo|<->|baz|bar<->(|-<->).baz); do
  base=${f%%(.(foo|<->|baz|bar<->(|-<->).baz))#}; extensions=${f#$base}
  new_base=${"$(openssl dgst -sha256 -hmac $secret <<<$base)"[-16,-1]}
  mv -i -- $f $new_base$extensions
done

zmv以下は、決定的なケースの1行のコードです。最初のコードを使用してデフォルトの.foo.終わりを表示します。この-wフラグは分解に役立ちます。

autoload zmv
secret=$(openssl rand -hex 32)
zmv -w '*.foo.*' '${"$(openssl dgst -sha256 -hmac $secret <<<$1)"[-16,-1]}.foo.$2'

任意の状況でzmvを使用することは、1つの変換段階から次の変換段階まで情報を保存する必要があるため、より困難です。zmv … '$(…; if …; then mapping[$base]=…; …)'ペアの割り当てはmappingコマンド置換サブシェル内にあるため、サブシェル内でのみ影響を与えるため、一部のコードをコマンド置換でラップできます。ただし、条件付きパラメーター割り当てを使用できます。${name=word}mapping[$base]、未設定の場合のみ設定されます。

typeset -A mapping; mapping=()
zmv -w '*.foo.*' '${mapping[${1}]=$(openssl rand -hex 16)}.foo.$2'

上記の(1.)のより複雑な例のように、未使用の分解でzmvを使用すると、.fooコードはより複雑になります。例として、ここにデフォルトbase名を格納するための一時変数として使用される決定的なケースへのzmv呼び出しがあります。これは${name::=word}、パラメータ拡張中に変数に代入し、拡張でその${…}[0]部分を抑制するために使用されます([0]zshが1から始まる配列要素と文字列文字に番号を付けるため、存在しない0番目の文字から部分文字列を取得します。[2,1]作業も可能)。

zmv  '*.(<->|baz|bar<->.baz)' '${${base::=${f%%(.(<->|baz|bar<->(|-<->).baz))#}}[0]}${"$(openssl dgst -sha256 -hmac $secret <<<$base)"[-16,-1]}.${f#$base}'

おすすめ記事