1. 概要

標準出力を変更せずに、コマンドの標準エラーをフィルタリングしたい場合があります。 たとえば、 grep を使用して、別のコマンドの標準エラーを処理したい場合があります。

pipes を使用してプロセスの出力をフィルタリングする場合、標準出力のみ、または標準出力とエラーをフィルタリングできます。 ただし、パイプを使用して標準エラーのみをフィルタリングすることはできません。

この記事では、この制限を克服するための2つのアプローチを学習します。

2. プロセス置換の使用

プロセス置換を使用すると、bashはコマンドの入力または出力のエイリアスとしてファイル名を設定します。 >(command)と書くと、コマンドの入力を表すファイル名が取得されます。 または、次のように書くこともできます <(コマンド) コマンドの出力を参照します。

grepを使用してどのように機能するかを見てみましょう。

$ echo This parameter: >(grep baeldung) is a filename to the command\'s input.
This parameter: /dev/fd/63 is a filename to the command's input.

ご覧のとおり、 bash は、コマンドの入力をファイル / dev / fd /63に置き換えました。

これをリダイレクトと組み合わせて、その「ファイル」に書き込みましょう。

$ echo -e "line 1: baeldung
line 2: linux" > >(grep baeldung)
line 1: baeldung

この場合、 echo の標準出力は、grepの標準入力に接続するファイルにリダイレクトされました。

Linuxには、3つの標準ファイル記述子があります。 標準入力( STDIN )はファイル記述子 0 であり、標準出力( STDOUT )はファイル記述子 1 であり、標準エラー( STDERR )は、ファイル記述子2です。 この概念を使用して、標準エラーのみをフィルタリングする代わりに、ファイル記述子2をリダイレクトすることもできます。

curl -v http://www.example.com を実行すると、HTML応答が標準出力に出力され、HTTPヘッダーが標準エラーに出力されます。 grep を介して標準エラーをリダイレクトし、AcceptHTTPヘッダーをフィルタリングしてみましょう。

$ curl -v http://www.example.com 2> >(grep Accept:)
> Accept: */*
<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

ご覧のとおり、 grep は標準エラーのみをフィルタリングし、HTMLコンテンツはそのまま残しています。

grepの出力が標準出力であることを考慮に入れる必要があります。 ただし、grepcurlの標準エラーをフィードしています。 これは、たとえば、フィルターを追加する場合に不利になる可能性があります。 grepフィルターに>&2を追加して、標準エラーを標準出力から分離してみましょう。

$ curl -v http://www.example.com 2> >(grep Accept: >&2)

これは、出力の混合を防ぐのに役立ち、grepAcceptヘッダーを標準エラーに出力します。 これにより、 2つの異なるフィルターを使用できます。1つは標準出力用で、もう1つは標準エラー用です。

追加しましょう grep“を使用して、標準出力をフィルタリングします。

$ curl -v http://www.example.com > >(grep "<title>") 2> >(grep Accept: >&2)
> Accept: */*
    <title>Example Domain</title>

ご覧のとおり、標準出力を1つのフィルターに通すことができました。 grep“、および別のフィルター grep Accept:による標準エラー。 grep Accept:からの出力を標準エラーにリダイレクトしたことに注意してください。 そうしなかったら、 grep“は、 grep Accept:からの出力もフィルタリングします。

3. ファイル記述子の交換

標準エラーのみをフィルタリングする別の方法は、ファイル記述子を交換することです。 標準出力と標準エラーを交換できるため、パイプを使用して、元々は標準エラーであった標準出力のみをフィルタリングできます。このスワップは、リダイレクトを使用して3つのステップで実行されます。

まず、標準出力のコピーとして、新しいファイル記述子3を作成します。 3>&1 。 次に、を使用して標準出力を標準エラーのコピーにします。 >&2 。 最後に、標準エラーをファイル記述子3のコピーにします。 2>&3 。 ファイル記述子3は標準出力のコピーであることに注意してください。 新しいファイル記述子3を作成したので、それを閉じます。 3>&-。

前のcurlの例を繰り返しましょうが、今回はファイル記述子を交換します

$ curl -v http://www.example.com 3>&1 >&2 2>&3 3>&- | grep Accept:
> Accept: */*
<!doctype html>
<html>
<head>
    <title>Example Domain</title>
...

これで、HTMLコンテンツをそのまま受け取り、 AcceptHTTPヘッダーのみをフィルタリングしました。

ファイルファイル記述子を交換したため、 curl はHTMLコンテンツを標準エラーに出力し、HTTPヘッダーを標準出力に出力します。 これは、元の動作の逆です。 元の動作を維持したい場合は、ファイル記述子を再度交換する必要があります。

ファイル記述子を元の意味に戻すために、コマンドとフィルターをサブシェルで囲み、ファイル記述子をもう一度交換します

$ (curl -v http://www.example.com 3>&1 >&2 2>&3 3>&- | grep Accept:) 3>&1 >&2 2>&3 3>&-

これで、元の標準出力をフィルタリングするために別のパイプを追加できます。

追加しましょう grep フィルタリングするにはセクション:

$ (curl -v http://www.example.com 3>&1 >&2 2>&3 3>&- | grep Accept:) 3>&1 >&2 2>&3 3>&- | grep "<title>"
> Accept: */*
    <title>Example Domain</title>

ご覧のとおり、最初のgrepはHTTPヘッダーのみをフィルタリングしました。 次に、最後のgrepはHTMLコンテンツのみをフィルタリングしました。

4. 結論

この記事では、標準エラーのみをフィルタリングする2つの方法を見ました。

最初に、プロセス置換を使用して標準エラーを別のプロセスにリダイレクトすることを検討しました。 次に、パイプと組み合わせたファイル記述子を交換しました。

さらに、標準誤差用のフィルターと標準出力用の別の異なるフィルターを使用する方法を見ました。