試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

bash,dash,zshにおける演算と外部コマンドの出力について

ここではbash,dash,zshのシェルにおいて演算結果と外部コマンドの出力の展開についてを扱う。どちらもその記述を行った部分について「展開」されるだけなので、それをそのまま(出力の全体もしくは一部として)表示してもシェル上の変数に代入してもよい。

演算

2つの丸括弧で計算式をくくって先頭に「$」を付けるとその計算の結果に展開される。

$ echo 123たす234は$((123+234))
123たす234は357

もちろん、0で割ろうとするとエラーとなる。メッセージの出かたはそれぞれのシェルで微妙に異なる。

bash$ echo $((2/0))
bash: 2/0: division by 0 (error token is "0")

dash$ echo $((2/0))
dash: arithmetic expression: division by zero: "2/0"

zsh$ echo $((2/0))
zsh: division by zero

分母が0でない割り算でも、zsh以外はうまく処理できないことがある。

$((1/5))

はいずれも「0」に展開されるが、zshでは小数点を付けると計算される。しかし、bash,dashではエラーになる。

bash$ echo $((1.0/5.0))
bash: 1.0/5.0: syntax error: invalid arithmetic operator (error token is ".0/5.0")

dash$ echo $((1.0/5.0))
dash: arith: syntax error: "1.0/5.0"

zsh$ echo $((1.0/5.0))
0.20000000000000001

外部コマンドの出力

1つの丸括弧でコマンド行をくくって先頭に「$」を付けるとそのコマンドの出力に展開される。これは入れ子にすることもできる。下は入れ子の例で、相対パスで渡されたファイルやディレクトリの場所を絶対パスに変換している。

$ INFILE=[ファイルやディレクトリの相対パスもしくは絶対パス]
$ INFILE=$(cd $(dirname ${INFILE}) && pwd)/$(basename ${INFILE})
$ echo ${INFILE}
[絶対パスが表示される]
$ unset INFILE

具体的な例として、ディレクト/tmp/work/にいるとして同ディレクトリのtest.txtを示す相対パス「./test.txt」がINFILEだとすると

[/tmp/work]$ INFILE=./test.txt
[/tmp/work]$ INFILE=$(cd $(dirname ${INFILE}) && pwd)/$(basename ${INFILE})
[/tmp/work]$ echo ${INFILE}
/tmp/work/test.txt
[/tmp/work]$ unset INFILE

このように絶対パスになっている。
外部コマンドの出力を扱う書き方として、バッククォート文字(`)2つで囲む書き方もあるが、入れ子にはできない。
(2009/11/16)バックスラッシュで内側のバッククォートをエスケープすると入れ子にすること自体は可能(bash,dash,zshで確認・id:Magicant氏に感謝)だが非推奨。また、(本記事とは関係ないが)tcshではエラーの原因となる。

$ for i in `seq 5`; do echo ${i}; done; unset i
1
2
3
4
5

上の例は

for i in $(seq 5); do echo ${i}; done; unset i

とも書ける。
いずれの形式においても、外部コマンドの出力はパイプで別のプロセスに渡された結果でもよい。

$ echo "HDD:$(nc 127.0.0.1 7634 | awk -F\| '{printf $4}')"
HDD:[温度の値]

関連記事:

使用したバージョン: