シュルスクリプトで、コマンドの前に代入を書くとコマンドを実行するときに一時的にシェル変数と環境変数を設定できて便利。

よくある用法

readで空白も読みたいときにIFS=""を指定する場合に

echo "*** WITHOUT IFS="
cal | while read X; do
    echo "$X"
done

echo "*** WITH IFS="
cal | while IFS= read X; do
    echo "$X"
done

実行結果

*** WITHOUT IFS=
September 2015
Su Mo Tu We Th Fr Sa
1  2  3  4  5
6  7  8  9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

*** WITH IFS=
   September 2015
Su Mo Tu We Th Fr Sa
       1  2  3  4  5
 6  7  8  9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30

てっきりこの代入は一時的だとおもっていたのだが、呼ばれるコマンドがシェル関数かコマンドかで挙動が違うらしい。


http://tiswww.case.edu/php/chet/bash/POSIX

31. Assignment statements preceding shell function calls persist in the
    shell environment after the function returns, as if a POSIX
    special builtin command had been executed.


試した環境
  • FreeBSD /bin/sh
  • CentOS /bin/dash
  • bash
  • bash -o posix
テストスクリプト
f() {
    echo "$X"
    /usr/bin/printenv X
}
g() {
    X="$X.g1" f
    X="$X.g2" f
}
h() {
    X="$X.h1" g
    X="$X.h2" g
}
X=m1 h
X="$X.m2" h
sh
m1.h1.g1
m1.h1.g2
m1.h2.g1
m1.h2.g2
.m2.h1.g1
.m2.h1.g2
.m2.h2.g1
.m2.h2.g2
dash
m1.h1.g1
m1.h1.g1.g2
m1.h1.g1.g2.h2.g1
m1.h1.g1.g2.h2.g1.g2
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2.h2.g1
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2.h2.g1.g2
bash
m1.h1.g1
m1.h1.g1
m1.h1.g2
m1.h1.g2
m1.h2.g1
m1.h2.g1
m1.h2.g2
m1.h2.g2
.m2.h1.g1
.m2.h1.g1
.m2.h1.g2
.m2.h1.g2
.m2.h2.g1
.m2.h2.g1
.m2.h2.g2
.m2.h2.g2
bash -o posix
m1.h1.g1
m1.h1.g1
m1.h1.g1.g2
m1.h1.g1.g2
m1.h1.g1.g2.h2.g1
m1.h1.g1.g2.h2.g1
m1.h1.g1.g2.h2.g1.g2
m1.h1.g1.g2.h2.g1.g2
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2.h2.g1
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2.h2.g1
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2.h2.g1.g2
m1.h1.g1.g2.h2.g1.g2.m2.h1.g1.g2.h2.g1.g2

まとめると

Shell 一時的か? 環境変数か?
fbsd sh Yes No
dash No No
bash Yes Yes
bash -o posix No Yes

続く

koie