Difference between ${} and $() in Bash [duplicate] Ask Question

Difference between ${} and $() in Bash [duplicate] Ask Question

I have two questions and could use some help understanding them.

  1. What is the difference between ${} and $()? I understand that () means running command in separate shell and placing $ means passing the value to variable. Can someone help me in understanding this? Please correct me if I am wrong.

  2. If we can use for ((i=0;i<10;i++)); do echo $i; done and it works fine then why can't I use it as while ((i=0;i<10;i++)); do echo $i; done? What is the difference in execution cycle for both?

ベストアンサー1

The syntax is token-level, so the meaning of the dollar sign depends on the token it's in. The expression $(command) is a modern synonym for `command` which stands for command substitution; it means run command and put its output here. So

echo "Today is $(date). A fine day."

will run the date command and include its output in the argument to echo. The parentheses are unrelated to the syntax for running a command in a subshell, although they have something in common (the command substitution also runs in a separate subshell).

(Perhaps also notice $((mathematical expression)) which allows you to perform simple integer arithmetic in the shell.)

By contrast, ${variable} is just a disambiguation mechanism, so you can say ${var}text when you mean the contents of the variable var, followed by text (as opposed to $vartext which means the contents of the variable vartext).

The braces are also used for parameter expansion; so, for example, ${var-default} produces the text default if $var is empty, ${var#bar} produces the value of $var with any occurrence of bar removed from the beginning of the string, etc etc. There are dozens of these; refer to the link for the full list.

The while loop expects a single argument which should evaluate to true or false (or actually multiple, where the last one's truth value is examined -- thanks Jonathan Leffler for pointing this out); when it's false, the loop is no longer executed. The for loop iterates over a list of items and binds each to a loop variable in turn; the syntax you refer to is one (rather generalized) way to express a loop over a range of arithmetic values.

A for loop like that can be rephrased as a while loop. The expression

for ((init; check; step)); do
    body
done

is equivalent to

init
while check; do
    body
    step
done

読みやすさのために、すべてのループ制御を 1 か所にまとめておくのは理にかなっています。しかし、このように表現するとわかるように、ループはループforよりもかなり多くのことを行いますwhile

もちろん、この構文はBash特有のものであり、古典的なBourneシェルでは

for variable in token1 token2 ...; do

(もう少しエレガントにするには、引数文字列にフォーマット コードechoが含まれていないことが確実であれば、最初の例の を避けることができます。%

date +'Today is %c. A fine day.'

この孤立した例では大きな違いはありませんが、可能な場合はプロセスを回避することは重要な考慮事項です。


余談ですが、多くの初心者は引用符として括弧を使おうとしますが、これはうまくいきません。これを説明するために、次のようなコードがあるとします。

# BROKEN example
var="foo bar"
if [ $var -eq foo bar ]; then
    echo "Victory! I have conquered this quirk of shell syntax."
fi

構文エラーが発生して苦労します。シェルはなぜ$varここに単一の値があることを認識しないのでしょうか? 中括弧を追加しましょう!

# still BROKEN
if [ ${var} -eq foo bar ]; then

問題は、ワイルドカード展開と変数置換の後に得られるのは単なる文字列だけだということです。シェルは

# still still BROKEN
if [ foo bar -eq foo bar ]; then

(または、より正確には、トークンのシーケンスif、、、、、、、、、、 )[を実行し、...fooを実行しようとします。これは、単一の値と、オプションでオペランドと 2 番目の値が続くことを想定しているため、構文エラーにbarなります。これを解決するには、次のように引用します。-eqfoobar];then[ foo bar[

if [ "$var" -eq "foo bar" ]; then

ifこれは、、、、、、、にトークン化され[、適切に解析されて実行さfoo barれます。(-eqfoo bar];thenまた括弧を追加します"${var}"が、これは完全に冗長です。;"foo bar"の後の引用符にも注意して-eqください。また、シェル変数を引用符で囲むのはいつですか?

おすすめ記事