スクリプトにコマンドオプションを追加するなど、変数を介して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全体をリダイレクトすることはできません。
別の解決策は次のとおりです。
#!/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
出力を表示したいコマンドのみ。
「方法」は他の回答でよく説明されています。 OPのコードが機能しない「なぜ」に対処したいと思います。
基調講演は出力リダイレクトはbefore変数展開としてマークされていますリダイレクトは実際には実行されます変数展開後(変数に保存されているファイル名に出力をリダイレクトできる理由)、しかしシェルは識別します変数が展開される前に後で処理するためのリダイレクト。
言い換えると、変数が展開されると、リダイレクト文字(<
または>
など)は考慮されます。これは、シェルがリダイレクトとして処理するコマンド文字列のどの部分をすでに特定しているためです。
詳細については、以下にリストされているステップ1および3を参照してください。
LESS='+/^SIMPLE COMMAND EXPANSION' man bash
それは「ディレクトリ名」として解釈されず、>
が引用されているため、文字どおりに処理されます(より具体的には、文字列>dev/null 2>&1
を送信しています。これを回避する唯一の方法は、 eval
または新しいシェルを生成します。
質問でほのめかされている「冗長」な問題については、代わりに次のようにしてください。
verbose=1
if (( verbose )); then
mkdir -v -p /foo
else
mkdir -p /foo > /dev/null 2>&1
fi
変数に多くのスペースがあり、適切に評価されません。 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
を使用するように変更されました。
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