web-dev-qa-db-ja.com

グロブマッチからランダム化されたアイテムを返す

zshの-​​glob qualifiersを使用すると、ファイル名のグロブパターンマッチングの結果をさまざまな方法で並べ替えることができます。たとえば、パターン*(om)は、変更タイムスタンプ順に並べられた、現在のディレクトリ内のすべての非表示でない名前と一致します。

ただし、ランダム化の順序を設定する方法が必要な場合があります(たとえば、ファイルのランダムサンプリングを取得するため)。私が見た限りでは、これを直接行う修飾子はありません。

質問:zshファイル名のグロブパターンからパス名のランダム化されたリストを取得するにはどうすればよいですか?

4
Kusalananda

ランダムソートキーを使用します( glob qualifieroe)::

_*(Noe\''REPLY=$RANDOM,$RANDOM'\')
_

説明:

  • oeの後には、1文字の区切り文字、コードのチャンク、および別の区切り文字が続きます。コードのチャンクには区切り文字が含まれていない場合があります。特殊文字は、glob修飾子自体を解析するときに解析されないように、エスケープする必要があります。
  • 区切り文字として_'_を使用し(エスケープする必要があるためバックスラッシュを使用)、存在する可能性のある特殊文字を保護するためにコードを_'_でラップします。このようにして、_'_が含まれていない限り、任意のコードを記述できます。
  • このコードのチャンクは、一致するファイル名ごとに順番に実行されます。
  • REPLYは最初にファイル名に設定され、コードがREPLYに設定したものはすべてソートキーとして使用されます)。

_$n_要素をランダムにサンプリングするには、_[…]_修飾子を追加します。

_*(Noe\''REPLY=$RANDOM,$RANDOM'\'[1,$n])
_

場合によっては、一部の要素が同じ並べ替えキーを取得するため、すべての順列が同じように発生する可能性は低く、並べ替え関数をディレクトリ順にリストに適用した結果を保持することをわずかに優先します¹が、バイアスは小さいです。バイアスを減らすために、_$RANDOM,$RANDOM_ではなく_$RANDOM_をソートキーとして使用します。_$RANDOM_は15ビットの数値であり、ファイルの数が2 ^ 15に近づくとバイアスが目立ちます。

わずかなバイアスが問題にならない場合は、_$RANDOM_で十分にサンプリングできることに注意してください。セキュリティを伴うものには適していません。安全なランダム置換が必要な場合は、GNU coreutils shuf を使用します。(お気に入りのOSにネイティブのshufがない場合何らかの理由でGNU coreutilsをインストールしたくない場合は、代わりに ibaraの再実装 を試すことができます。)

_securely_permuted=("${(0)$(printf '%s\0' *(N) | shuf -z))}")
_

または、コマンドラインの長さの制限に遭遇する可能性のある単純なバージョン:

_securely_permuted=("${(0)$(shuf -z -- *(N)))}")
_

¹ 実験的には、並べ替えは安定しています(たとえば、*(omoe\''REPLY=1'\')*(om)と同等ですが、*(oe\''REPLY=1'\')からの順序は*(oN)と一致しません。いずれにせよ、それは特定の順序を支持する小さなバイアスです。