を使用find
して/home
ディレクトリ内のすべてのPDFファイルを表示すると、が表示されますaccess denied
。それらを排除するために私は試しました:
find /home -iname "*.pdf" | grep -v "access denied"
ただし、結果は同じです。これらの線を取り除くにはどうすればよいですか?
を使用find
して/home
ディレクトリ内のすべてのPDFファイルを表示すると、が表示されますaccess denied
。それらを排除するために私は試しました:
find /home -iname "*.pdf" | grep -v "access denied"
ただし、結果は同じです。これらの線を取り除くにはどうすればよいですか?
回答:
access denied
出力がエラーであり、にパイプされるSTDOUTの代わりにSTDERRで送信されたため、試してもうまくいきませんでしたgrep
。
STDERRのみをリダイレクトすることで、これらのエラーの発生を回避できます。
find /home -iname "*.pdf" 2>/dev/null
または、David Foersterがコメントしたように、 STDERRをより簡潔に閉じることができます
find /home -iname "*.pdf" 2>&-
ただし、実際には他のユーザーではなく自宅のみを検索したいのではないかと思います。
find ~ -iname "*.pdf"
それによってエラーがスローされる場合は、ローカル構成に誤った所有権がある可能性があります。調査する必要があります。
sudo chown $USER: ~/.gvfs ~/.dbus
2>&-
です。機能不全のファイル記述子にエラーメッセージを書き込もうとしても、GNU findはそれ自体を終了しません。所有権の問題sudo chown -R $USER: ...
は、が所有していないファイルが多い場合により効果的$USER
です。
拒否されたアクセスは、おそらくではstderr
なくに印刷されていstdout
ます。
これを試して:
find /home -iname "*.pdf" 2>&1 | grep -v "access denied"
は2>&1
からの出力をstderr
にリダイレクトするstdout
ので、grep -v
はその処理を実行できます。(デフォルトでは、|
パイプのみでstdout
あり、ではありませんstderr
。)
2>&1
...私はbashのエキスパートではないので、それが正しくない場合は、そう言ってください:)
bash
、UbuntuにはPOSIXモードを除いてそれがあります。私はそれが最良の解決策だと思います-悪意を持って名前access denied
が付けられたファイルは引き続き表示されます。
あなたは、おそらく何を意味するかである-which「アクセス許可が拒否された」find
とき、あなたはので、ファイルのパーミッション-ではなく、「アクセス拒否」のアクセス何かすることはできませんあなたがUbuntuのショーに。
これを正しく行う(そしておまけとして、エラーメッセージが同じである限り、他の* nixに移植できる)完全に一般的なコマンドは次のとおりです。
(find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
(通常、いくつかの引数をに渡しますfind
。それらは最初のリダイレクトの前に移動し3>&1
ます。)
ただし、多くの場合、より単純なものを使用できます。たとえば、おそらくプロセス置換を使用できます。詳細は次のとおりです。
2つの典型的なアプローチは、stderrを破棄するか(Zannaの回答のように)、またはstderrをstdoutにリダイレクトして、stdoutをフィルター処理します(Android Devの回答のように)。これらは、簡単に記述できるという利点があり、多くの場合妥当な選択ですが、これらのアプローチは理想的ではありません。
stderrに送信されたすべてを破棄する(たとえば、nullデバイスにリダイレクトしたり、nullデバイスを2>/dev/null
使用して閉じたりする)と2>&-
、「Permission denied」以外のエラーが見つからないというリスクが生じます。
「Permission denied」は、実行中find
に見られる最も一般的なエラーですが、考えられる唯一のエラーとはほど遠く、別のエラーが発生した場合は、それについて知りたい場合があります。特に、find
開始点が存在しない場合は、「そのようなファイルまたはディレクトリはありません」と報告します。開始点が複数あるfind
場合でも、いくつかの有用な結果が返され、機能しているように見えることがあります。たとえばa
、c
存在していb
ても存在しない場合、find a b c -name x
結果はa
になり、「そのようなファイルまたはディレクトリはありません」の場合b
、結果はになりc
ます。
stdoutとstderrを一緒にstdoutに結合し、それをパイプするgrep
か、または他のコマンドでそれをフィルターに掛けて(2>&1 | grep ...
またはと|& grep ...
同様に)、フィルターされているメッセージを含む名前のファイルを誤ってフィルターに掛けるリスクがあります。
たとえば、「Permission denied」を含む行を除外すると、「Permission denied messages.txt」のようなファイル名を表示する検索結果もドロップされます。これはおそらく偶然に起こりますが、検索を妨害するためにファイルに特別に細工された名前を付けることも可能です。
結合されたストリームのフィルタリングには別の問題があり、これをより選択的にフィルタリングすること(grep -vx 'find: .*: Permission denied'
パイプの右側など)では軽減できません。find
アクション-print
を指定しない場合の暗黙のアクションを含む一部のアクションは、stdoutが端末かどうかに基づいてファイル名を出力する方法を決定します。
?
代わりに印刷されます。grep
)でパイプ処理するとfind
、ターミナルが表示されなくなります。(より正確には、そのstdoutが端末にならないようにします。)次に、奇妙な文字が文字どおりに出力されます。しかし、パイプの右側にあるすべてのコマンドが(a)「Permission denied」メッセージのように見える行を削除し、(b)残っているものを出力する場合、それでも、find
ターミナルの一種の悪意の対象になります。検出は防止することを目的としています。man find
ファイル名を出力する各アクションの動作を含む詳細については、「UNUSUAL FILENAMES」セクションを参照してください。(「他のユーザーの制御下にあるデータの印刷での検索結果の行動...の多くは、」)のセクションも参照してください。3.3.2.1、3.3.2.2、および3.3.2.3のGNUのfindutilsリファレンスマニュアル。上記の珍しいファイル名の説明は、GNU findに関係しています。これは、find
Ubuntuを含むGNU / Linuxシステムでの実装です。
あなたが本当にここにしたいことは残すことであるSTDOUTパイピングながらそのまま標準エラー出力をしますgrep
。残念ながら、これには単純な構文はありません。|
パイプstdout、および両方のストリームをパイプbash
する|&
ためのいくつかのシェル(を含む)サポート-または2>&1 |
、最初にを使用してstderrをstdoutにリダイレクトできます。これは同じ効果があります。しかし、一般的に使用されるシェルは、stderrのみをパイプする構文を提供しません。
あなたはまだこれを行うことができます。ぎこちないです。1つの方法は、stdoutをstderrと交換して、検索結果がstderrにあり、エラーがstdoutにあるようにgrep
します。次に、フィルタリングのためにstdoutをパイプします。
find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'
通常find
、開始点(検索する場所、通常はディレクトリです)や述語(テストとアクション)などの引数をに渡します。これらはargs
上記の代わりになります。
これは、スワップする2つの標準ストリームの1つを保持する新しいファイル記述子を導入し、それらをスワップするリダイレクトを実行して、新しいファイル記述子を閉じることによって機能します。
3>&1
ファイル記述子3をstdoutにリダイレクトします。これにより、stdout(ファイル記述子1)がその後リダイレクトされるときに、元のstdoutを引き続き簡単に書き込むことができます。1>&2
stdoutをstderrにリダイレクトします。ファイル記述子3はまだ元のstdoutなので、引き続きアクセスできます。2>&3
stderrを元のstdoutであるファイル記述子3にリダイレクトします。3>&-
不要になったファイル記述子3を閉じます。ただし、この方法には、検索結果がstderrに送信され、エラーがstdoutに送信されるという欠点があります。このコマンドを対話型シェルで直接実行していて、出力をパイプしたりリダイレクトしたりしない場合は、問題はありません。それ以外の場合は、問題がある可能性があります。そのコマンドをスクリプトに入れてから、誰か(おそらくは後で)がその出力をリダイレクトまたはパイプ処理すると、期待どおりに動作しません。
解決策は、出力のフィルタリングが完了した後でストリームを元に戻すことです。上記と同じリダイレクトをパイプラインの右側に適用しても、これは達成されません。パイプ|
のみがstdoutであるため、パイプラインのその側は、最初にstderrに送信された出力のみを受信し(ストリームが交換されたため)、元の出力は受信しませんstdout出力。代わりに、を使用(
)
して上記のコマンドをサブシェル(関連)で実行し、それにスワッピングリダイレクトを適用できます。
(find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
これを機能させるのは、特にサブシェルではなく、グループ化です。必要に応じて、以下を使用できます{
;}
。
{ find args 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'; } 3>&1 1>&2 2>&3 3>&-
サポートできるシステム(UbuntuなどのGNU / Linuxシステムを含む)のBashを含む一部のシェルでは、プロセス置換を実行できます。これにより、コマンドを実行し、そのストリームの1つにリダイレクトできます。あなたは、リダイレクトすることができますfind
にコマンドの標準エラー出力をgrep
、それをフィルタリングコマンド、およびそのリダイレクトgrep
stderrにコマンドの標準出力を。
find args 2> >(grep -Fv 'Permission denied' >&2)
このアイデアは、Android Devの功績によるものです。
1>&2
。私はを使用しましたが>&2
、これは同等(関連)です。お好きな方をご利用ください。が、bash
支持体には、置換を処理し、sh
Ubuntuのであるdash
ありません、。この方法を使用しようとすると、「構文エラー:予期しないリダイレクト」が発生しますが、stdoutとstderrを交換する方法は引き続き機能します。ときさらに、bash
で実行POSIXモード、プロセス・置換のためのサポートがオフになっています。
bash
POSIXモードで実行される1つの状況は、sh
1として呼び出された場合です。したがって、FedoraのようなOSでがbash
提供さ/bin/sh
れている場合、またはUbuntuで/bin/sh
シンボリックリンクをbash
自分に指定した場合でもsh
、POSIXモードをオフにする事前のコマンドがないと、スクリプトでプロセス置換は機能しません。このメソッドをスクリプトで使用する場合、最善の策は、の代わりにを#!/bin/bash
上部に配置#!/bin/sh
することです。
1:この状況でbash
は、起動スクリプトでコマンドを実行した後、POSIXモードを自動的にオンにします。
これらのコマンドをテストできると便利です。これを行うにtmp
は、現在のディレクトリのサブディレクトリを作成し、それにいくつかのファイルとディレクトリを追加し、それらの1つからアクセス許可を取り除いて、で「アクセス許可が拒否されました」エラーをトリガーしfind
ます。
mkdir tmp; cd tmp; mkdir a b c; touch w a/x 'a/Permission denied messages.txt' b/y c/z; chmod 0 b
ディレクトリの一つであるアクセスは、その名前に「許可が拒否された」とのファイルが含まれています。find
リダイレクトやパイプなしで実行すると、このファイルが表示されますが、アクセスできない別のディレクトリの実際の「Permission denied」エラーも表示されます。
ek@Io:~/tmp$ find
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘./b’: Permission denied
stdoutとstderrの両方をパイプgrep
し、 "Permission denied"を含む行をフィルタリングすると、エラーメッセージは表示されなくなりますが、名前にそのフレーズが含まれるファイルの検索結果も非表示になります。
ek@Io:~/tmp$ find |& grep -Fv 'Permission denied'
.
./a
./a/x
./c
./c/z
./w
./b
find 2>&1 | grep -Fv 'Permission denied'
同等であり、同じ出力を生成します。
上記の「アクセスが拒否されました」をエラーメッセージからのみ除外し、検索結果からは除外しない方法は成功しています。たとえば、stdoutとstderrが交換されるメソッドは次のとおりです。
ek@Io:~/tmp$ (find 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find args 2> >(grep -Fv 'Permission denied' >&2)
同じ出力を生成します。
別のエラーメッセージをトリガーして、「Permission denied」というテキストを含まない stderrに送信された行が引き続き許可されるようにすることができます。たとえば、ここではfind
、現在のディレクトリ(.
)を1つの開始点として実行しましたが、存在しないディレクトリfoo
を別の開始点として実行しました。
ek@Io:~/tmp$ (find . foo 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
.
./a
./a/Permission denied messages.txt
./a/x
./c
./c/z
./w
./b
find: ‘foo’: No such file or directory
find
標準出力がまだターミナルであるかどうかの確認また、どのコマンドが改行などの特殊文字を文字どおりに表示するかを確認することもできます。(これは上記のデモとは別に行うことができ、tmp
ディレクトリにある必要はありません。)
名前に改行を含むファイルを作成します。
touch $'abc\ndef'
通常、の開始点としてディレクトリを使用しfind
ますが、ファイルも機能します。
$ find abc*
abc?def
stdoutを別のコマンドにパイピングすると、改行が文字どおりに出力され、2つの別々の検索結果abc
との誤った印象が生じdef
ます。それをテストすることができますcat
:
$ find abc* | cat
abc
def
stderrだけをリダイレクトしても、この問題は発生しません。
$ find abc* 2>/dev/null
abc?def
それを閉じることもしません:
$ find abc* 2>&-
abc?def
配管すると問題grep
が発生します。
$ find abc* |& grep -Fv 'Permission denied'
abc
def
(交換|&
とは2>&1 |
等価であり、同じ出力を生成します。)
stdoutとstderrを入れ替えてstdoutをパイプしても問題は発生しません—find
のstdoutはstderrになり、パイプされません。
$ find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied'
abc?def
そのコマンドをグループ化してストリームをスワップバックしても問題は発生しません。
$ (find abc* 3>&1 1>&2 2>&3 3>&- | grep -Fv 'Permission denied') 3>&1 1>&2 2>&3 3>&-
abc?def
({
;}
バージョンは同じ出力を生成します。)
プロセス置換を使用してstderrをフィルタリングしても、問題は発生しません。
$ find abc* 2> >(grep -Fv 'Permission denied' >&2)
abc?def