20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

シェルスクリプトのwhile文の中の変数を外で使う方法

Last updated at Posted at 2017-01-22

シェルスクリプトではwhile文の中で変数の値を書き換えてもwhile文を抜けた後に値の変更が反映されていないことがある。
説明を省略して対処法だけ書くと、パイプを使わずにヒアドキュメントを使えばよい。

2020/4/12追記
Process Substitutionという機能を使った方がいいらしいです。
参考記事:https://qiita.com/kawaz/items/6fd4cd86ca98af644a05

サンプル

一つ目のwhile文ではパイプで文字列を入力しているため、while文の後で$iを参照しても1になってしまうが、二つ目のwhile文はヒアドキュメントを使っているので、後で$iを参照すると変更が反映されて6が表示される。

#!/bin/bash

STR="\
a
b
c
d
e"

echo "Using pipe"

i=1
echo "$STR" | while read line ; do
    echo $i, $line
    i=$(( $i + 1 ))
done
echo $i

echo
echo "Using heredocument"

i=1
while read line ; do
    echo $i, $line
    i=$(( $i + 1 ))
done << END
$STR
END
echo $i

実行結果

Using pipe
1, a
2, b
3, c
4, d
5, e
1

Using heredocument
1, a
2, b
3, c
4, d
5, e
6

##解説

パイプを使うと次のコマンドは子プロセスとしてforkされる。そのため、サンプルコードの一つ目のwhile文は別のプロセスとなり、その中で変更された$iは親プロセスには反映されず、while文の外で$iの値を使用することができない。
だが、二つ目のヒアドキュメントを使ったwhile文では、同じプロセスでwhile文が実行されるためwhile文の外でも$iの値を使用することができる。

また、プロセスをforkするときに変数はコピーされるため、パイプを使ったwhile文でも親プロセスの変数をwhile文の中で使用できる。そのため、サンプルコードではi=0からではなく、while文の前で初期化されたi=1から始まっている。

20
22
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?