- - PR -
シェル変数を引数にしたときの空白の扱いについて
1
投稿者 | 投稿内容 | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
投稿日時: 2002-07-01 09:28
こせきと申します。
シェル変数内での空白の扱いについて教えてください。 以下のような引数を表示するだけのコマンドprintargを 作っておいて、
下のシェルスクリプトを実行すると、
結果は下のようになりました。
最初と最後の結果については予想通りだったのですが 2番目のものが意外でした。 この2番目のような引数の渡し方をする既存のシェルスクリプトが あるのですが、VARの値を変えることで、1番目のように空白を含む値を コマンドに渡すことはできないでしょうか。 また、2番目のように空白で分割する処理はあまり使い道がないように 思うのですが(実際zshでやってみると2番目と3番目の結果は 同じになるようですし)なぜこのように処理されるんでしょうか? ご存知のかたいらっしゃいましたら、教えてください。 よろしくお願いいたします。 | ||||||||||||
|
投稿日時: 2002-07-01 23:55
私は主にbashを使っているのでbashで説明しますね。ここの内容なら、そんなにshと変わらないはずなので・・・。(違ったらごめんなさい)
> また、2番目のように空白で分割する処理はあまり使い道がないように > 思うのですが(実際zshでやってみると2番目と3番目の結果は > 同じになるようですし)なぜこのように処理されるんでしょうか? bash> VAR="'aaa bbb' 'ccc ddd eee'" bash> printarg $VAR とやると、まずVAR変数が文字列へ展開されます。 その際、変数の中の"や'はただの文字列として扱われますので、VARは¥'aaa bbb¥' ¥'ccc ddd eee¥'と変換されてしまいます。実際に実行されるコマンドラインは bash> printarg ¥'aaa bbb¥' ¥'ccc ddd eee¥' と同じになります。つまり'は¥でエスケープされるのでクオートしたことにならず、'の間にある空白が無視されずに単語分割されてしいます。実行結果は 1:'aaa 2:bbb' 3:'ccc 4:ddd 5:eee' となってしまいます。 う〜ん、簡単な対処法はちょっと思いつきません。別の変数に格納するという方法以外ではシェル上で回避するのは無理なんじゃないかと思います。 注)半角だと2重になってしまいますので、¥は全角で書いています。 [ メッセージ編集済み 編集者: H2 編集日時 2002-07-02 00:00 ] | ||||||||||||
|
投稿日時: 2002-07-02 10:27
追加レス: zshとbashの違い。
zshとbashで引数の展開のステップが違います。zshの場合、引数内の変数を展開した後に単語分割を行いません。そのため、zshでは2番目と3番目の結果が同じになります。 bashの場合、"$VAR"とやると、VARの中身が "" 内に展開されます。"" はクオートと呼ばれ、単語分割を無視しますので、3番目の結果のように一つの引数として扱われます。 $VAR だけだと、単語の分割が変数の展開後に行われますので、2番目の結果になります。(前述したように、変数内の ' はエスケープされます) zshの場合、 履歴展開 (History Expansion) → プロセス置換 (Process Substitution) → パラメータと変数の展開 (Parameter Expansion) → コマンド置換 (Command Substitution) → 算術式展開 (Arithmetic Expansion) → ブレースの展開 (Brace Expansion) → パス名の展開 (Filename Expansion) → パス名の作成 (Filename Generation) bashの場合、 ブレースの展開 (brace expansion) → チルダの展開 (tilde expansion) → パラメータと変数の展開 (parameter and variable expansion) → コマンド置換 (command substitution) → 算術式展開 (arithmetic expansion) → 単語の分割 (word splitting) → パス名の展開 (pathname expansion) ちなみに、zshでも明示的に指示すれば単語の分割を行えます。詳しくはmanページを見てください。 [ メッセージ編集済み 編集者: H2 編集日時 2002-07-02 10:30 ] [ メッセージ編集済み 編集者: H2 編集日時 2002-07-02 10:32 ] | ||||||||||||
|
投稿日時: 2002-07-02 10:40
すみません、続けて書き込みます・・・。zshのマニュアルを読んでたら有効な方法が見つかりましたので。
> この2番目のような引数の渡し方をする既存のシェルスクリプトが > あるのですが、VARの値を変えることで、1番目のように空白を含む値を > コマンドに渡すことはできないでしょうか。 zsh上でならば
としてみてください。(z)というフラグをつけることでパラメータ展開時にクオートを取り込んだ単語分割もやってくれます。 結果は 1:aaa bbb 2:ccc ddd eee -------------------------- 1:'aaa bbb' 2:'ccc ddd eee' -------------------------- 1:'aaa bbb' 'ccc ddd eee' です。' が邪魔でしたら、${(Q)${(z)VAR}}としてみてください。 (Q)は一番最上位のクオートを取り除きます。 [ メッセージ編集済み 編集者: H2 編集日時 2002-07-02 10:48 ] | ||||||||||||
|
投稿日時: 2002-07-02 10:41
VARはクォーティングで調理済みですから、平の文字列
のコマンド解釈を強制しないと。 eval ./printarg $VAR; でドウでしょう。 | ||||||||||||
|
投稿日時: 2002-07-02 10:50
> う〜ん、簡単な対処法はちょっと思いつきません。別の変数に格納するという方法以外で
> はシェル上で回避するのは無理なんじゃないかと思います。 (前言撤回します) おおっ。なるほど、すごくシンプルだ。evalはそういう使い方をするんですね。シェルは奥が深いなぁ・・・。 | ||||||||||||
|
投稿日時: 2002-07-02 19:57
H2さん、MMXさん、ありがとうございました!
目からウロコが落ちました。 回答いただいな内容を手がかりに bashのマニュアルも読んでみたんですが
というあたりがポイントなのですね。 で、evalがそれらの単語(というか引数)を結合して、もう一度シェルに 処理させると。 コマンドラインの裏ではこんな複雑な処理が行われているんですねー。 びっくり です。 ちなみにスペースをうまく扱ってくれなかったのは Apache Antの起動スクリプトなんですが、evalを加えてやってみます。 どうもありがとうございました。 #あ、あとすいません、/usr/bin/shは/bin/shの間違いです。変なとこ間違えてた… |
1