シェルスクリプト-スペースが含まれる文字列を扱う

シェルにおけるスペース(空白文字)の動作

シェルは、引数にスペースを含む場合、スペースを一つのかたまり(意味のある文字列)の区切りとして認識します。

例えば、「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

関連ページ