web-dev-qa-db-ja.com

bash:変数を使用してstderr | stdoutリダイレクトを格納します

スクリプトにコマンドオプションを追加するなど、変数を介してstdoutとstderrをリダイレクトする方法はありますか?

たとえば、私はスクリプトを持っています:

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
mkdir $OPT 123/123/123 $TEST

OPTが-pで問題なく置き換えられていることがわかり、bashはそれをオプションとして解釈します。ただし、リダイレクトはディレクトリ名として解釈されます。

$ ./test.sh 
+ TEST='>/dev/null 2>&1'
+ OPT='-p -v'
+ mkdir -p -v 123/123/123 '>/dev/null' '2>&1'
mkdir: created directory `123/123'
mkdir: created directory `123/123/123'
mkdir: created directory `>/dev'
mkdir: created directory `>/dev/null'
mkdir: created directory `2>&1'

$ VARはリダイレクトであり、dirsの名前ではないというbashを言う方法はありますか?.

PS。間違っている可能性がありますが、スクリプトからオプションの詳細出力または非詳細出力を作成したいと思います。しかし、非冗長モードでも出力が必要なので、スクリプト内のいくつかのコマンドからのみ、stdoutとstderr全体をリダイレクトすることはできません。

18
rush

別の解決策は次のとおりです。

#!/bin/bash

verbose=0

exec 3>&1
exec 4>&2

if ((verbose)); then
  echo "verbose=1"
else
  echo "verbose=0"
  exec 1>/dev/null
  exec 2>/dev/null
fi

echo "this should be seen if verbose"
echo "this should always be seen" 1>&3 2>&4

それから加えて 1>&3 2>&4出力を表示したいコマンドのみ。

18
enzotib

「方法」は他の回答でよく説明されています。 OPのコードが機能しない「なぜ」に対処したいと思います。

基調講演は出力リダイレクトはbefore変数展開としてマークされていますリダイレクトは実際には実行されます変数展開後(変数に保存されているファイル名に出力をリダイレクトできる理由)、しかしシェルは識別します変数が展開される前に後で処理するためのリダイレクト。

言い換えると、変数が展開されると、リダイレクト文字(<または>など)は考慮されます。これは、シェルがリダイレクトとして処理するコマンド文字列のどの部分をすでに特定しているためです。

詳細については、以下にリストされているステップ1および3を参照してください。

LESS='+/^SIMPLE COMMAND EXPANSION' man bash
5
Wildcard

それは「ディレクトリ名」として解釈されず、>が引用されているため、文字どおりに処理されます(より具体的には、文字列>dev/null 2>&1を送信しています。これを回避する唯一の方法は、 evalまたは新しいシェルを生成します。

質問でほのめかされている「冗長」な問題については、代わりに次のようにしてください。

verbose=1
if (( verbose )); then
    mkdir -v -p /foo
else
    mkdir -p /foo > /dev/null 2>&1
fi
3
Chris Down

変数に多くのスペースがあり、適切に評価されません。 evalを使用して設定します。

#!/bin/bash -x
TEST=">/dev/null 2>&1"
OPT='-p -v'
eval mkdir $OPT 123/123/123 $TEST

これにより、$ OPTを1つの(-p)ではなく2つの引数(-vおよび-p -v)に分割し、$ TESTで同じにすることができます。また、現在のディレクトリにdevディレクトリが存在することはほとんどないため、/dev/nullを使用するように変更されました。

1
Arcege

enzotibの答えは、優れたファイル記述子の魔法を使用していますが、より簡単な解決策は、evalの行を使用することです(ただし、doesプロセスのオーバーヘッドを追加します)。

$ rm /tmp/foo
$ ll /tmp/foo
ls: cannot access /tmp/foo: No such file or directory
$ FOO=">/tmp/foo"
$ date $FOO
date: invalid date '>/tmp/foo'
$ cat /tmp/foo
cat: /tmp/foo: No such file or directory
$ eval date $FOO
$ cat /tmp/foo
Thu Dec 13 14:08:17 EST 2018
0
Joe Casadonte