bashscriptで読み取り専用変数を設定しました。
readonly NO_OUTPUT="1>/dev/null 2>&1"
私のスクリプトの一部のコマンドでこの変数を使用すると、$ {NO_OUTPUT}がリスト内の他のファイルであると思うようなエラーが発生するのはなぜですか?
たとえば、次のようなものがあります。
make install ${MAKE_PREFIX} ${NO_OUTPUT}
最後に、次の内容でエラーが生成されます。 make: *** No rule to make target '1>/dev/null 2>&1'. Stop.
ただし、次のように変更すると:
make install ${MAKE_PREFIX} 1>/dev/null 2>&1
予想通り正確に動作しますか?
他のコマンド(cp、rmなど)でも同様の問題が発生しましたが、エラーが発生しました。
答え1
make install ${MAKE_PREFIX} ${NO_OUTPUT}
呼び出さmake
れるとinstall
、分割+globの結果はMAKE_PREFIX変数の内容に適用され、分割+globの結果はNO_OUTPUT変数の内容に別々の引数として適用されます。
おそらくあなたは次のようなものが欲しいでしょう:
if [ -n "$VERBOSE" ]; then
nooutput() { "$@"; }
else
nooutput() { "$@" > /dev/null 2>&1; }
fi
nooutput make install "$MAKE_PREFIX"
内容が別の引数である MAKE_PREFIX 変数をmake
呼び出すために使用され、詳細情報表示モードで実行されない場合、stdout および stderr が /dev/null にリダイレクトされます。install
ここで別名を使用することもできます。
if [ -n "$VERBOSE" ]; then
alias nooutput=' '
else
alias nooutput='> /dev/null 2>&1 '
fi
nooutput make install "$MAKE_PREFIX"
bash
POSIX以外のモードでシェルを使用している場合でもshopt -s expand_aliases
。
コードでエイリアスを使用するときにもエイリアスを定義する必要があります。読む(いいえ走る)。
では、zsh
次のこともできます。グローバルエイリアスはコマンド位置になくても拡張されるため、次のようにできます。
if [ -n "$VERBOSE" ]; then
alias -g '$NOOUTPUT$='
else
alias -g '$NOOUTPUT$=> /dev/null 2>&1'
fi
make install "$MAKE_PREFIX" $NOOUTPUT$
$NOOUTPUT$
代わりに、ここではパラメータ拡張は行われず、nullで置き換えられるか、コードを読み取るときにコードが評価されるかなり前に置き換えられること$NOOUTPUT
をより明確にするためにここで使用されます。$NOOUTPUT$
> /dev/null 2>&1
答え2
シェルは、各部分を拡張する前に各部分が何であるかを識別するために、コマンドラインから各単語(トークン、部分)を区切ります。リダイレクトは、コマンドライン解析フェーズの近くに設定されます。はるかに後で変数の拡張一つリダイレクトされた単語にはできません。
いいえ、配列変数や単純変数も機能しません。
$ NO_OUTPUT=( "1>/dev/null" "2>&1" )
$ printf '%s\n' "${NO_OUTPUT[@]}"
1>/dev/null
2>&1
$ a="1>/dev/null"
$ b="2>&1"
$ printf '%s\n' "$a" "$b"
1>/dev/null
2>&1
$ printf '%s\n' 1>/dev/null 2>&1
$
したがって、いいえ。変数の内容をシェルワードトークンに変換する方法はありません。
とは別にeval
。しかし、evalは通常セキュリティevil
リスクがあります。
答え3
eval
文字列を受け取り、コマンドとして実行するコマンドを使用すると、コードは次のようになります。
eval make install ${MAKE_PREFIX} ${NO_OUTPUT}
なぜこれが起こるのか、そしてあなたが望む結果を得るためのより良い方法については、以下を見てください。変数に格納されたコマンドをどのように実行できますか?。