3
set +f; rm *; touch a; for i in *; do touch b; echo $i; done

私が試したすべてのシェル (dash、ksh、zsh、bash) で、上記のスニペットは「a」のみを出力します。Cで同じことを実装すると(ファイルを作成するreaddirでopendir/loop)、「a」のみが出力されます。ただし、ディレクトリに十分な数のファイル (~4096) が含まれている場合、C 実装は通常 "b" も出力します。(つまり、readdir は、opendir の後に作成されたファイルの結果を返します)。この場合にシェルがどのように応答する必要があるかを示すシェル標準には何もありません。標準準拠のシェルは、グロブの後に作成されたファイルのループに入ることができますか? これは、シェルがアクションを実行する前にグロブ全体をメモリに読み込まないことを意味するため、非常に望ましい特性です。ディレクトリに多くのファイルが含まれていることが予想される状況では、グロブをメモリに読み込むだけで数秒かかることがよくあります。

ループに入る前にグロブ全体をメモリに読み込まないシェル実装はありますか?

4

1 に答える 1

3

いいえ。グロブが展開されるコンテキストは、すべての展開が処理され、結果の単語が反復のために不変の方法で保存される通常のコマンド展開コンテキストと本質的に同じです。for-in ループでは、遅延反復子は使用できません。もちろん、展開には副作用があり、グロブと混在する可能性があるため、熱心に評価する必要があります。これが、find -exec [+;]物事を同時に行うことが可能な場合に globstar よりも頻繁に推奨される理由です。

この 4096 の問題については、何も言えません。この2つは本当に比べ物にならないと思います。Shell for..in は、単語を展開して反復するだけです。

関連する FAQ は、割り当てられる次の値を先読みするなどのことができるかどうかです。私の知る限り、単語リストへの特別なアクセスを提供する bourne のようなシェルはありません。そのためには配列を使用する必要があります。基本的に、すべての制限はfor..in配列を介して克服できます。

これは、私が Bash 用に書いた面白い遅延 coproc ジェネレーターです。それはかなり役に立たない。

coproc x { while :; do find . -type f -maxdepth 1 -exec sh -c 'read; echo "$1"' -- {} \;; done; };

while :; do
    echo 1 >&"${x[1]}"
    read -ru "${x[0]}" file
    echo "$file"
    sleep 1
done

そして、for..in実際には質問とは関係のないもう 1 つの情報 -- ksh93 と Bash の git devel ブランチでは、興味深い方法で「制御変数」を利用することが可能です。

function f {
    nameref x # Chet may decide not to emulate the typeset -n aliases

    for x; do
        x=hi
    done
}

typeset -a arr
f 'arr['{0..3}']'
typeset -p arr # arr=(hi hi hi hi)

各反復は、指定されたオブジェクトへの参照を x に割り当てます。もちろん、ksh では、任意の複雑なデータ型にすることができます。これは、何らかの形で怠惰をシミュレートするために悪用される可能性があると思います。残念ながら、このパターンは mksh では機能しないようです。

編集for xこれを書いて以来、多くのシェルが実際に構文を最適化することを発見したことを忘れていました。少なくともfor x inコピーオンライトであり、shiftまたはsetがループ内で使用されている場合にのみ位置パラメーターのコピーを作成すると思います。

于 2012-10-15T14:18:42.817 に答える