シェルスクリプト-スペースが含まれる文字列を扱う
シェルにおけるスペース(空白文字)の動作
シェルは、引数にスペースを含む場合、スペースを一つのかたまり(意味のある文字列)の区切りとして認識します。
例えば、「Program Files」というディレクトリに移動する場合、以下のコマンドを実行しても、「Program」というディレクトリに移動する動作となります。
$ cd Program Files
「Program Files」ディレクトリに移動するためには、「""(ダブルクォーテーション)」でくくるか、スペース文字をエスケープする必要があります。
$ cd "Program Files"
$ cd Program\ Files
シェルスクリプトにおけるスペース(空白文字)の動作
シェルスクリプトにおいても、スペース(空白文字)を含む文字列は、スペースを区切り文字として一つのかたまりと認識します。
これは、IFS(Internal Field Separator:フィールドセパレータ環境変数)に区切り文字としてスペースが設定されているためです。
例えば、スペースが混在するファイルを用意します。
$ cat datas.txt
I choose a lazy person to do a hard job.
Because a lazy person will find an easy way to do it.
シェルスクリプトで1行ずつファイル読み込みをするスクリプトを作成します。
$ cat show_lines.sh
#!/bin/sh
filename=$1
for line in `cat ${filename}`
do
echo ${line}
done
スクリプトを実行すると、スペース毎の出力となります。
$ cat show_lines.sh datas.txt
I
choose
a
lazy
...
IFSを「改行コード」のみに設定したスクリプトに修正します。
$ cat show_lines.sh
#!/bin/sh
PRE_IFS=$IFS
IFS=$'\n'
filename=$1
for line in `cat ${filename}`
do
echo ${line}
done
IFS=$PRE_IFS
結果、行単位でデータを読み出すことに成功します。
$ ./space.sh datas.txt
I choose a lazy person to do a hard job.
Because a lazy person will find an easy way to do it.
コマンド引数のスペース区切り
コマンド引数においても、スペース(空白文字)を含む文字列は、スペースを区切り文字として一つのかたまりと認識します。
スペース文字のある引数を適切に渡すためには、「""(ダブルクォーテーション)」でくくるか、スペース文字をエスケープする必要があります。
引数を子プロセスに全部渡す場合
例えば、以下のような親シェルから全引数を渡して、子シェルをバックグラウンドで呼び出す(キック処理)構造のスクリプトを作成します。
$ cat parent.sh
#!/bin/sh
sh $@ &
$ cat child.sh
#!/bin/sh
echo $1 > $2
child.shの第一引数にスペースのある文字を指定すると、スペースを引数の区切り文字と判断してしまい、思う動作となりません。以下のコマンドでは、「user01」という文字列を「pass01」というファイルに書き込むと判断されてしまいます。
$ ./parent.sh ./child.sh "user01 pass01" file1
対処法としては、parent.shの「$@」をダブルクォーテーションでくくります。
- 「$@」はダブルクォートで囲んだ場合、それぞれの引数を個別にダブルクォートで囲んで展開します。
- 「$*」はダブルクォートで囲んだ場合、全引数を一つにまとめて展開します。
$ cat parent.sh
#!/bin/sh
sh "$@" &
この修正により、引数にスペースがある文字列を指定しても、個別引数として扱う動作となります。
$ ./parent.sh ./child.sh "user01 pass01" file1
$ cat file1
user01 pass01