GNU find -execdirコマンドがBSD findとは異なる動作をするのはなぜですか?

GNU find -execdirコマンドがBSD findとは異なる動作をするのはなぜですか?

私のOSXでは、次のようにfindデフォルトのBSDと一緒にGNUをインストールしました。findbrew install findutils

私が知る限り、BSDはfindPOSIX標準に準拠し、GNUはそれをオプションにします(これによると郵便はがき)、これは予想される出力に多くの不一致を引き起こします。

たとえば、

BSDルックアップ

$ find -L /etc -execdir echo {} ';' | head
etc
AFP.conf
afpovertcp.cfg
aliases
aliases.db
apache2
extra
httpd-autoindex.conf
httpd-dav.conf
httpd-default.conf

GNUを探す

$ gfind --version
find (GNU findutils) 4.4.2
$ POSIXLY_CORRECT=1 gfind -L /etc -execdir echo {} ';' | head
/etc
/etc/AFP.conf
/etc/afpovertcp.cfg
/etc/aliases
/etc/aliases.db
/etc/apache2
/etc/apache2/extra
/etc/apache2/extra/httpd-autoindex.conf
/etc/apache2/extra/httpd-dav.conf
/etc/apache2/extra/httpd-default.conf
gfind: `echo' terminated by signal 13
gfind: `echo' terminated by signal 13
... endless loop here

-L注:上記のリンクを私の/etcリンクとして使用していますprivate/etc

GNU find マニュアルで POSIX 標準に従うことを指定できることがわかりますが、POSIXLY_CORRECT上記の例ではこれは機能しません。

上記の例では、GNU findが同じ出力を持つように強制する別の方法があります(例:POSIX標準)。

無限ループに加えて、GNUは相対ファイル名を印刷しますが、BSDがフルパスを印刷するのはなぜですか?

ベストアンサー1

これはない無限ループこれは、SIGPIPEを使用してGNUが死亡をfind報告することですecho(なぜなら、stdoutのパイプのもう一方の端はhead死亡時に閉じていたからです)。

-execdirPOSIX が指定されていません。ために-exec何もないPOSIX仕様これは、コマンドが SIGPIPE によって終了した場合にfind終了する必要があることを意味します。

-execdirしたがって、POSIXが指定されている場合、gfindBSDよりもPO​​SIX仕様が高くなる可能性がありますfind(質問が示すように、サブプロセスがSIGPIPEで終了したときにBSDが終了を見つけたと仮定すると、FreeBSDはfind私のテストに含まれておらず実行されます)。echo ループ内各ファイルについて(GNU findのように無限ではありません)。

最も一般的なケースでは、findSIGPIPEのために子が終了すると終了する方が良いと主張することができますが、-exectedコマンドは標準出力でパイプを閉じること以外の理由でSIGPIPEによって終了する可能性があるため、終了することはfind許可されます。

GNUを使用すると、コマンドが失敗した場合に終了するfindように指示できます。find

find . ... \( -exec echo {} \; -o -quit \)

find実装がstderrでchild-deathシグナルを報告することを許可するのか、それとも許可しないのかについては、ここを使ってとにかく-execdirPOSIXの範囲外ですが、代わりに使用すると-execgfind-execdir非準拠のケースになりそうです。

仕様は次のようにfind言います。「標準エラーは診断メッセージに固有です。」だけでなくそこで言った:

デフォルトの動作:このセクションが「標準エラーは診断メッセージにのみ使用する必要があります」とリストされている場合、特に明記しない限り、終了ステータスがエラーが発生したことを示す場合にのみ、診断メッセージを標準エラーに送信する必要があります。ユーティリティは、このボリュームのPOSIX.1-2008で説明されているように使用されます。

これはfind、この場合、ゼロ以外の終了ステータスは返されないため、stderrにメッセージを出力しないことを示します。

このテキストによると、findGNUとFreeBSDはどちらも次の状況で非準拠です。

$ find /dev/null -exec blah \;; echo "$?"
find: `blah': No such file or directory
0

どちらもエラーを報告しますが、終了ステータスをゼロ以外に設定しません。だから私はこの質問は、オースティングループ(POSIXの背後にある人)メーリングリストで質問されました。

コマンドを次のように変更した場合は注意してください。

(trap '' PIPE; find -L /etc -execdir echo {} \; | head)

echoそれでもすべてのファイルで実行され、まだ失敗しますが、今回はechoエラーメッセージが報告されます。


これでfilenamevs /etc/filenamevsの内容./filenameが示されています。

-execdir繰り返しますが、基準オプション、誰が正しいかどうかを示すテキストはありません。-execdirこれはBSDによって導入され、find後でGNUによってコピーされましたfind

GNUはfind意図的にいくつかの変更(改善)をしました。たとえば、./コマンドに渡された引数にファイル名を追加します。これはfind . -execdir cmd {} \;、exampleで始まるファイル名に問題がないことを意味します。-

実際に-L -execdir親ディレクトリに基づいてファイルパスを渡さないのは、実際には抜け穴GNUバージョン4.3.0〜4.5.8に影響しますfind。 4.5.9で修正されましたが、開発ブランチにあり、まだ新しいブランチはありません。安定出版以降(2015年12月22日現在、差し迫った)。

詳細については、findutilsメーリングリストを参照してください。

必要なのがPortable各ファイルのデフォルト名を印刷することであれば、/etc次のようにすることができます。

find -L /etc -exec basename {} \;

またはより効率的に:

find -L ///etc | awk -F / '/\/\// && NR>1 {print last}
                          {if (NF > 1) last = $NF
                           else last = last "\n" $NF}
                          END {if (NR) print last}'

次のように単純化できます。

find -L /etc | awk -F / '{print $NF}'

ファイルパスに改行文字が含まれていないことを確認できる場合(IIRC、一部のOS / Xバージョンは/ etcに対応するファイルがあります)

GNUly:

find -L /etc -printf '%f\n'

かどうかについて:

find -exec echo {} \;

内部に協会POSIXに言及していますか?

いいえ、コマンド呼び出しとして、これはPOSIXではありません。 ㅏスクリプトこれは非準拠です。

POSIXでは、find少なくとも1つのパスを指定する必要がありますが、オプションではない最初の引数がorで始まり、述部find-たとえばfind!または()の場合、指定されていない動作は維持されるため、GNUfind動作は維持されます。はい互換性、バグ報告(または照会述語を表しても最初の引数をファイルパスとして扱う)、実装の顔に赤いペイントを散布するなど、それが動作にPOSIXLY_CORRECT影響を与える理由はありません。find

おすすめ記事