find(1): 特定のファイル名で失敗するようにアスタリスクのワイルドカードを実装する方法は?

find(1): 特定のファイル名で失敗するようにアスタリスクのワイルドカードを実装する方法は?

ファイル名がUTF-8のファイルシステムにファイル名エラーがあります。 zsh:、Latin 1D�sinstallerによる実際の名前は、「削除」を意味する野蛮なフランス語です。 Zshはこれを一致させませんが、ワイルドカードと一致させます。これは私が期待する動作です。D$'\351'sinstallerDésinstaller[[ $file =~ '^.*$' ]]*

今私はまだ実行時にそれを見つけることを期待していますfind . -name '*'。実際、ファイル名がこのテストに失敗するとは決して予想しません。ただし、ファイルのLANG=en_US.utf8場合いいえLANG=Cが表示されたら(またはen_US、または)を設定する必要があり''ます。

質問: その後の実装は何ですか?結果をどのように予測しますか?

情報: Arch Linux 3.14.37-1-lts, find(GNU findutils) 4.4.2

ベストアンサー1

本当に良いボーナスですね。 GNU findのソースコードを少し見てみると、これはfnmatch無効なバイトシーケンス(pred_name_commonin pred.c)の動作方法で帰結すると言いたいと思います。

b = fnmatch (str, base, flags) == 0;
(...)
return b;

このコードはfnmatch戻り値が0かどうかをテストしますが、エラーをチェックしません。これにより、エラーが「一致しない」と報告されます。

何年も前に、*破損したファイル名でもパターンに対して常にtrueを返すようにこのlibc関数の動作を変更することが提案されましたが、私が知っている限り、このアイデアは拒否されました(参照:https://sourceware.org/ml/libc-hacker/2002-11/msg00071.html):

fnmatchが無効なマルチバイト文字を検出した場合は、「*」がその文字列と一致するようにシングルバイト一致で置き換える必要があります。

なぜこれがより良いかより正確ですか?既成の方法はありますか?

Stéphane Chazelasがコメントと2002年の同じスレッドで述べたように、これは無効な文字をブロックしないシェルで実行されるglob拡張と一致しません。おそらくもっと混乱しているのは、リバーステストが名前が破損したファイルだけを一致させることです(bashでcreate fileを使用touch $'D\351marrer' $'Touch\303\251' $'\346\227\245\346\234\254\350\252\236')。

$ find -name '*'
.
./Touché
./日本語

$ find -not -name '*'
./D?marrer

したがって、あなたの質問に答えるには、この場合の動作を理解し、関数のfnmatch戻り値をどのように処理するかを知ることで、findこれを予測できます。おそらく文書を読むだけでは答えが見つかりません。

おすすめ記事