シェルスクリプトで外部ファイルに記述された変数を利用する方法

シェルスクリプトを作成していると、設定変数が記述された設定ファイルを外部ファイルとして利用したい事がある。 そんな時、どのようにすればよいのだろうか?

1.外部ファイル(設定ファイル)で定義されている変数を利用する場合

外部ファイル内で変数を定義し、その変数をスクリプトファイル内で使用している場合、「.(ドット)」後にそのファイルのパスを記述することで、そのファイルを読み込む事が出来る。 例えば、スクリプトファイル「test.sh」で、設定ファイル「conf.txt」に記述されている変数「USER」をechoで出力したいとする。

●スクリプトファイル「test.sh」

#!/bin/sh

echo $USER

●設定ファイル「conf.txt」

USER=HOGE

このとき、上記の状態のままで出力しても、変数「USER」は空のため、空の文字列が出力されるだけだ。 では、source文を追記し、設定ファイルを指定するようにしてみよう。

●スクリプトファイル「test.sh」

#!/bin/sh

. ./test.txt
echo $USER

さて、それでは実際にコマンドを実行してみよう。

$ sh test.sh
HOGE

これは、例えば以下のような構成でも利用できる。

ユーザ名の変数(上図ではUSER)などを、別の設定ファイル上で変数として利用し、それをスクリプトファイル側でまとめる、といった使い方だ。 実際に、動作をみてみよう。以下のような構成でスクリプトを実行してみる。

●スクリプトファイル(test.sh)

#!/bin/sh

. ./USER.txt
. ./COMMAND.txt
`$COMMAND`

●設定ファイル(ユーザ名)

USER="test"

●設定ファイル(コマンド)

COMMAND="chmod 777 /home/${USER}"

実際に実行した結果がこちら。

$ sh -x test.sh
+ . ./USER.txt
+ USER=test
+ . ./COMMAND.txt
+ COMMAND=chmod 777 /home/test
+ chmod 777 /home/test
+

なお、読込むファイル名の前は「.(ドット)」の他、bashであれば「source」と記述しても読込みが可能だ。

2.スクリプトファイルで定義されている変数を外部ファイル(設定ファイル)にテキストとして記述する場合

最初に言っておくと、こちらはあまり一般的なやり方では無いと思う。 スクリプトファイル内で変数を定義しておき、外部ファイルにその変数を用いたテキストを記述。そしてスクリプトファイル内でその変数を含んだテキストを展開させるというもの。

この場合、1で行っていた外部ファイルの読込み方法は意味をなさない。なぜなら、外部ファイル内では特に変数として定義している訳では無いからだ。そして、普通にcatなどで読込みを行っても、変数は展開されない。 ではどうすればよいのだろうか?

UNIXやLinuxには、evalというコマンドがある。このコマンドは、引数を一度に変換して実行するというものだ。 これを利用して、以下のようにスクリプトを作成する。以下の例では、変数「HOST_NAME」にホスト名を記述し、それを外部ファイル側で利用している。

●スクリプトファイル(test.sh)

#!/bin/sh
HOST_NAME=`hostname`

while read line;
do
    COMMAND=${COMMAND}`eval "echo $line"`"\n" ;
done<./test.txt
echo "$COMMAND"

●外部ファイル(test.txt)

open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/${HOST_NAME}
lcd /tmp
put aaa.txt

上記のように、外部ファイル4行目で変数を指定している。 これを実行すると、以下のように出力される。

$ sh -x test.sh
+ hostname
+ HOST_NAME=test-vm-ubuntu
+ read line
+ eval echo open 192.168.0.xxx
+ echo open 192.168.0.xxx
+ COMMAND=open 192.168.0.xxx\n
+ read line
+ eval echo user USER PASSWORD
+ echo user USER PASSWORD
+ COMMAND=open 192.168.0.xxx\nuser USER PASSWORD\n
+ read line
+ eval echo ascii
+ echo ascii
+ COMMAND=open 192.168.0.xxx\nuser USER PASSWORD\nascii\n
+ read line
+ eval echo cd /home/${HOST_NAME}
+ echo cd /home/test-vm-ubuntu
+ COMMAND=open 192.168.0.xxx\nuser USER PASSWORD\nascii\ncd /home/test-vm-ubuntu\n
+ read line
+ eval echo lcd /tmp
+ echo lcd /tmp
+ COMMAND=open 192.168.0.xxx\nuser USER PASSWORD\nascii\ncd /home/test-vm-ubuntu\nlcd /tmp\n
+ read line
+ eval echo put aaa.txt
+ echo put aaa.txt
+ COMMAND=open 192.168.0.xxx\nuser USER PASSWORD\nascii\ncd /home/test-vm-ubuntu\nlcd /tmp\nput aaa.txt\n
+ read line
+ echo open 192.168.0.xxx\nuser USER PASSWORD\nascii\ncd /home/test-vm-ubuntu\nlcd /tmp\nput aaa.txt\n
open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/test-vm-ubuntu
lcd /tmp
put aaa.txt

無事、変数が展開されて出力されていることが確認できた。

ちなみに、なぜwhileで一行づつ処理をさせているかというと、こうしないと改行が表現されないからである。 たとえば、以下のように改行を含んだ変数ごと読込みを行うようにコードを書き換えたとする。

#!/bin/sh
HOST_NAME=`hostname`

COMMAND=`cat $1`
eval "echo "$COMMAND""

すると、動作は以下のようになってしまう。

$ sh -x test.sh test.txt
+ hostname
+ HOST_NAME=test-vm-ubuntu
+ cat test.txt
+ COMMAND=open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/${HOST_NAME}
lcd /tmp
put aaa.txt
+ eval echo open 192.168.0.xxx user USER PASSWORD ascii cd /home/${HOST_NAME} lcd /tmp put aaa.txt
+ echo open 192.168.0.xxx user USER PASSWORD ascii cd /home/test-vm-ubuntu lcd /tmp put aaa.txt
open 192.168.0.xxx user USER PASSWORD ascii cd /home/test-vm-ubuntu lcd /tmp put aaa.txt

一行ならば上記のやり方でも問題無いが、改行を表現したいのであればwhileと組み合わせた方が良いだろう。 なお、whileでのやり方も改行コードを変数に代入して表現している。そのため、場合によっては別の変数に値を再度代入するとよいだろう。

※なお、「/bin/sh」ではなくbashを使用した場合、もっと簡単に上記の処理は実施出来る。

●スクリプトファイル(test.sh)

#!/bin/bash
HOST_NAME=`hostname`

COMMAND=`eval "echo \"$(< $1)\""`
echo "$COMMAND"

上記内容でコマンドを実行した場合の出力がこちら。

$ bash -x test3.sh test.txt
++ hostname
+ HOST_NAME=test-vm-ubuntu
++ eval 'echo "open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/${HOST_NAME}
lcd /tmp
put aaa.txt"'
+++ echo 'open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/test-vm-ubuntu
lcd /tmp
put aaa.txt'
+ COMMAND='open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/test-vm-ubuntu
lcd /tmp
put aaa.txt'
+ echo 'open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/test-vm-ubuntu
lcd /tmp
put aaa.txt'
open 192.168.0.xxx
user USER PASSWORD
ascii
cd /home/test-vm-ubuntu
lcd /tmp
put aaa.txt

以上。