引用符で囲まれた変数が空の場合、どうすれば何も展開できませんか?


21

スクリプトを実行しているとします:

some-command "$var1" "$var2" ...

そして、var1空のイベントでは、空の文字列の代わりに何も置き換えないで、実行されるコマンドが次のようになるようにします。

some-command "$var2" ...

ではなく:

some-command '' "$var2" ...

変数をテストして条件付きで含めるよりも簡単な方法はありますか?

if [ -n "$1" ]; then
    some-command "$var1" "$var2" ...
    # or some variant using arrays to build the command
    # args+=("$var1")
else
    some-command "$var2" ...
fi

bash、zshなどで何にも拡張できないパラメーター置換はありますか?残りの引数でグロビングを使用したい場合があるので、それを無効にして変数の引用符を外すことはオプションではありません。


私はこれを見て、おそらくこれを使用したことは知っていましたが、検索するのが難しいことがわかりました。Michaelが構文を示したのでunix.stackexchange.com
muru

何らかのパラメーター置換であることがわかっている場合、ページのパラメーター展開セクションを調べなかったのはなぜmanですか?(-;
フィリポス

1
@Philippos当時は何を知っていたのか、以前に見たり使ったりしたことしか知りませんでした。既知の既知および未知の既知。:(
muru

1
質問自体の引数を保持するために配列を使用することに言及するための追加のCookieポイント。
-ilkkachu

回答:


29

Posix準拠のシェルBashには ${parameter:+word}次のものがあります

場合は、パラメータが未設定またはヌルである、nullが代入されなければなりません。それ以外の場合は、単語の展開(または、単語が省略された場合は空の文字列)に置き換えられます。

だからあなたはちょうどすることができます:

${var1:+"$var1"}

そして、しているvar1チェックすること、および"$var1"それのセットと非空(通常の二重引用規則で)場合に使用します。それ以外の場合は、何にも拡張されません。ここではすべてではなく、内側の部分のみが引用されていることに注意してください。

同じことがzshでも機能します。変数を繰り返す必要があるため、理想的ではありませんが、希望どおりに機能します。

set-but-empty変数を空の引数に展開する場合は、${var1+"$var1"}代わりに使用します。


1
私には十分です。したがって、これでは、全体が引用されるのではなく、word一部のみが引用されます。
ムル

1
「bash、zshなど」(およびQ&Aアーカイブ)を求める質問に応じて、これがposix機能であることを反映するように編集しました。私のコメントの後に質問に/ bashタグを追加したとしても。(-;
フィリポス

2
私は間違いでの編集の自由を取った:++
-ilkkachu

POSIX準拠のソリューションに感謝します!私は潜在的なチョークポイントスクリプトにsh/ を使用しようとしていますdash。そのため、Bashに頼らずに誰かが物事がどのように可能であるかを示すとき、私はいつも感謝しています。
JamesTheAwesomeDude

私は反対の効果を探していました(nullで始まる場合、他の何かに拡張します)。このロジックは、次のように+を-に変更することで反転できることがわかりました。$ {empty_var:-replacement}
Alex Jansen

5

zsh引用符を省略すると、デフォルトでこれが行われます。

some-command $var1 $var2

実際、パラメーター展開の周りにzshで引用符が必要な唯一の理由zsh、パラメーター展開を引用しないときに他のシェルに影響する他の問題(暗黙的なsplit + glob)

splitとglobを無効にすると、他のPOSIX風のシェルでも同じことができます。

(IFS=; set -o noglob; some-command $var1 $var2)

今、私はあなたの変数が0または1の値を持つことができる場合、それは配列であり、スカラー変数ではなく、使用する必要があると主張します:

some-command "${var1[@]}" "${var2[@]}"

var1=(value)whenを使用しvar1て、1つの値を含める場合、var1=('')1つの空の値を含める場合、および値var1=()を含めない場合を使用します。


0

私は、bashスクリプトでrsyncを使用してこれに遭遇しました。bashスクリプトは、ドライラン-nを切り替えるために、またはなしでコマンドを開始しました。rsyncといくつかのgnuコマンドは''、有効な最初の引数として使用され、存在しない場合とは異なる動作をすることがわかります。

nullパラメーターはほとんど完全に見えないため、デバッグにはかなり時間がかかりました。

rsyncリストの誰かが、この問題を回避し、コーディングを大幅に簡素化する方法を教えてくれました。正しく理解できれば、これは@StéphaneChazelasの最後の提案のバリエーションです。

いくつかの個別の変数でコマンド引数を作成します。これらは、問題に合った任意の順序またはロジックで設定できます。

次に、最後に変数を使用して、すべてを適切な場所に配置して配列を構築し、それを実際のコマンドの引数として使用します。

このように、コマンドは、引数のバリエーションごとに繰り返されるのではなく、コード内の1つの場所でのみ発行されます。

空の変数は、このメソッドを使用して消えます。

evalの使用は非常に嫌われていることは知っています。すべての詳細を覚えているわけではありませんが、この方法で機能させるために必要なようです-空白が埋め込まれたパラメーターの処理と関係があります。

例:

dry_run=''
if [[ it is a test run ]]
then
  dry_run='-n'
fi
...
rsync_options=(
  ${dry_run}
  -avushi
  ${delete}
  ${excludes}
  --stats
  --progress
)
...
eval rsync "${rsync_options[@]}" ...

それは私が質問で説明したことを行うための悪い方法です(条件付きで引数の配列を構築する)。変数を引用符で囲まずに残すことにより、誰があなたが自分自身をオープンにしている問題を知っています。
ムル

@muruあなたは正しいですが、私はまだこのようなものが必要です。他の回答のテクニックを使用して修正する方法がわかりません。コードフラグメントをすべてまとめて適切な方法で実行できるのは素晴らしいことです。Stephaneの最後のオプションを使ってプレイするつもりです。
ジョー


これに戻りました。例に感謝します。それは理にかなっている。私はそれで仕事をするつもりです。
ジョー

ここにも同様の使用例がありますが、次のようなことができます。if ["$ dry" == "true"]; 次に、dry = "-n"; fi ...そのため、変数dryがtrueの場合、-nにし、通常どおりrsyncコマンドをビルドして、次のようにします:rsync $ {dry1:+ "$ dry1"} ... if if null何も起こりません。そうでなければ、コマンドで-nになります
Freedo
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.