シェルから PHP クライアントでコマンド実行。
よくあるケースですが、コマンドと引数の展開でハマったので備忘録に。
1 2 3 4 5 | #!/bin/sh php index.php a b php index.php "a" 'b' |
例えば上記のようなベタなコマンドだったら、どちらの引数も a と b が受け取れます。
では、こんなケースはどうでしょうか。
1 2 3 4 5 6 7 | #!/bin/sh CMD1="php index.php a b" ${CMD1} CMD2="php index.php \"a\" 'b'" ${CMD2} |
CMD1 の結果は冒頭のものと同様ですが、CMD2 の結果は以下のようになります。
a にはダブルクォーテーションが、b にはシングルクォーテーションが付いてしまっていますね。
“a”
‘b’
今回はこの問題に対応していきます。
PHPのコマンド生成
上ではシンプルな例を書きましたが、実際には csv ファイルの各列を引数に持たせて一部の項目だけシングルクォーテーションで囲みたいのですよね。
以下を「test.csv」とします。
1 2 3 | a,b,c d,e,f g,h,i |
こんなシェルをイメージしてみてもらえますか。
1 2 3 4 5 6 7 8 | #!/bin/sh while read line; do if [ "${line}" != "" ]; then CMD1=`echo ${line} | awk -F',' '{print "php index.php "$1" "$2" \047$3\047"}'` echo ${CMD1} fi done < test.csv |
結果は以下のようになります。
このコマンドをターミナルで実行すれば問題なく処理されます。
php index.php a b ‘c’
php index.php d e ‘f’
php index.php g h ‘i’
PHPコマンドが意図通りに動かないケース
しかし、この CMD1 の変数をそのまま実行すると意図通りには動作しません。
1 2 3 4 5 6 7 8 | #!/bin/sh while read line; do if [ "${line}" != "" ]; then CMD1=`echo ${line} | awk -F',' '{print "php index.php "$1" "$2" \047$3\047"}'` ${CMD1} fi done < test.csv |
冒頭の実行結果を見てもらうとわかりますが、シングルクォーテーションで囲んでいる部分の展開がうまくいっていません。
そこで eval の登場です。
$(eval echo “${CMD1}”)
先に「echo “${CMD1}”」を評価させてから実行させてしまえば問題ないですね。
1 2 3 4 5 6 7 8 | #!/bin/sh while read line; do if [ "${line}" != "" ]; then CMD1=`echo ${line} | awk -F',' '{print "php index.php "$1" "$2" \047$3\047"}'` $(eval echo "${CMD1}") fi done < test.csv |
もちろん、引数にダブルクォーテーションやシングルクォーテーションがなければ、ここでハマることはありません。
こうやって気付ける機会があるのがいいのか悪いのか・・・。
まとめ
シェルで PHP の引数付きコマンド(シングルクォーテーション付き)を実行する方法を紹介してきました。
引数の文字列に、エスケープが必要な記号や半角スペースなどが入ってくる可能性を考えるとシングルクォーテーションで囲んでおきたいですよね。
シェルのコマンドや変数の展開について理解しておかないと、今回のようにハマることになるので復習したいと思います。