「アクセスが拒否されました」行を削除しています


9

を使用findして/homeディレクトリ内のすべてのPDFファイルを表示すると、が表示されますaccess denied。それらを排除するために私は試しました:

find /home -iname "*.pdf" | grep -v "access denied"

ただし、結果は同じです。これらの線を取り除くにはどうすればよいですか?


回答:


19

access denied出力がエラーであり、にパイプされるSTDOUTの代わりにSTDERRで送信されたため、試してもうまくいきませんでしたgrep

STDERRのみをリダイレクトすることで、これらのエラーの発生を回避できます。

find /home -iname "*.pdf" 2>/dev/null

または、David Foersterがコメントしたように、 STDERRをより簡潔に閉じることができます

find /home -iname "*.pdf" 2>&-

ただし、実際には他のユーザーではなく自宅のみを検索したいのではないかと思います。

find ~ -iname "*.pdf"

それによってエラーがスローされる場合は、ローカル構成に誤った所有権がある可能性があります。調査する必要があります。


3
Grrr、なぜ人々はいつも私を30秒以上殴っているのですか?:\
You'reAGitForNotUsingGit 2017

見つける:「/home/ihsan/.gvfs」:「/home/ihsan/.dbusを」:アクセスが拒否された見つけるのアクセスは、コマンドのため、拒否された〜
solfish

そのために何か問題がありますか?はい私もテストするために私が作成した他のユーザーのホームディレクトリにしたい
solfish

2
@solfish私が知る限り、これらのファイルはあなたが所有する必要があります。あなたがしたいかもしれませんsudo chown $USER: ~/.gvfs ~/.dbus
Zanna

1
でstderrを閉じるのに十分なはず2>&-です。機能不全のファイル記述子にエラーメッセージを書き込もうとしても、GNU findはそれ自体を終了しません。所有権の問題sudo chown -R $USER: ...は、が所有していないファイルが多い場合により効果的$USERです。
David Foerster 2017

8

拒否されたアクセスは、おそらくではstderrなくに印刷されていstdoutます。

これを試して:

find /home -iname "*.pdf" 2>&1 | grep -v "access denied"

2>&1からの出力をstderrにリダイレクトするstdoutので、grep -vはその処理を実行できます。(デフォルトでは、|パイプのみでstdoutあり、ではありませんstderr。)


しかし、この2>&1は、stderrが存在する場合にstdoutに送信することを意味しますか?
solfish 2017

@solfishうん、それがまさにポイントです:)
You'reAGitForNotUsingGit 2017

「|」の前に理解できないのは 出力として; 私たちはちょうどstderrを正しくしましたか?「|」の後 入力として、これを入手しました
solfish 2017

@solfishさて、約1年半前にこの問題に遭遇し、別の方法を使用しそれを修正することができました。しかし、私の回答の下のコメントは単に使用することを提案しています2>&1...私はbashのエキスパートではないので、それが正しくない場合は、そう言ってください:)
You'reAGitForNotUsingGit

@AndroidDev代わりに、この別の方法をこの回答に追加することをお勧めします。Etan Reisnerの批判は、プロセス置換は移植性がないということでした。しかしbash、UbuntuにはPOSIXモードを除いてそれがあります。私はそれが最良の解決策だと思います-悪意を持って名前access deniedが付けられたファイルは引き続き表示されます。
Eliah Kagan 2017

4

あなたは、おそらく何を意味するかである-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場合でも、いくつかの有用な結果が返され、機能しているように見えることがあります。たとえばac存在してい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.13.3.2.2、および3.3.2.3GNUのfindutilsリファレンスマニュアル

上記の珍しいファイル名の説明は、GNU findに関係しています。これは、findUbuntuを含む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つを保持する新しいファイル記述子を導入し、それらをスワップするリダイレクトを実行して、新しいファイル記述子を閉じることによって機能します。

  • ファイル記述子1はstdoutで、2はstderrです(リダイレクトされていない0はstdinです)。ただし、他のファイル記述子を使用してリダイレクトすることもできます。これは、ファイルまたはデバイスを開く、または開いたままにするために使用できます。
  • 3>&1 ファイル記述子3をstdoutにリダイレクトします。これにより、stdout(ファイル記述子1)がその後リダイレクトされるときに、元のstdoutを引き続き簡単に書き込むことができます。
  • 1>&2stdoutをstderrにリダイレクトします。ファイル記述子3はまだ元のstdoutなので、引き続きアクセスできます。
  • 2>&3 stderrを元のstdoutであるファイル記述子3にリダイレクトします。
  • 3>&- 不要になったファイル記述子3を閉じます。
  • 詳細については、stdoutではなくstderrをパイプする方法を参照してくださいおよびIOリダイレクション-stdoutとstderrのスワッピング(詳細)、特にstderrのみをフィルターにパイプします

ただし、この方法には、検索結果が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、それをフィルタリングコマンド、およびそのリダイレクトgrepstderrにコマンドの標準出力を。

find args 2> >(grep -Fv 'Permission denied' >&2)

このアイデアは、Android Devの功績によるものです。

が、bash 支持体には、置換を処理し、shUbuntuのであるdashありません、。この方法を使用しようとすると、「構文エラー:予期しないリダイレクト」が発生しますが、stdoutとstderrを交換する方法は引き続き機能します。ときさらに、bashで実行POSIXモード、プロセス・置換のためのサポートがオフになっています。

bashPOSIXモードで実行される1つの状況は、sh1として呼び出された場合です。したがって、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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.