質問: ``` #!/bin/bash fuga=" string" echo ${fuga} | sed -e 's|^\s||' ``` 出力 ``` tring ``` これはどんな使用ですか?環境依存でしょうか?
回答: シェルの挙動 ====== シェルは与えられたコマンドライン文字列に対して変数展開 (variable expansion)、ワード分割 (word splitting)、パス名展開 (pathname expasion) などを実行し、その結果をコマンドとして実行します。 `echo ${fuga}` がどのように解釈されるかというと: 1. 変数展開が実行され `echo string` と解釈される (`echo` と `string` の間に (スペース 2 つ)) 2. ワード分割により空白文字 (1 文字以上のスペースやタブなど) で分割され `echo` と `string` の 2 要素として解釈される。 3. `echo` コマンドにコマンドライン引数 1 つ `string` を指定して実行する。 4. `echo` コマンドの実行により `string` が出力される。 このようにワード分割の過程で `${fuga}` の先頭にあったスペースが失われたものが `echo` に渡され、結果 `sed` には `string` だけが渡されます。 コマンドライン中のスペースなどをワード分割の対象外にするには `\` (バックスラッシュ) でエスケープしたり `"` (ダブルクォート) か `'` (シングルクォート) で括ってエスケープする必要があります。変数に含まれるスペースなどのワード分割を防ぐにはダブルクォートで括って変数展開する必要があります。 sed の違いによる正規表現の違い ================= `sed` が対応する正規表現は「BRE」(basic regular expressions、基本正規表現) であって「ERE」(extended regular expressions、拡張正規表現) ではありません。よって正規表現 `\s` はBRE としては `s` と等価であり、これは `s` にだけマッチします。 しかし GNU sed などの特殊な sed は BRE ではなく ERE 的な BRE として解釈する機能が実装されており、正規表現 `\s` は「空白文字」にマッチします。(GNU sed は `--regexp-extended` オプションを指定することにより ERE が利用できるのに、何故こんな余計な機能を設けたのかは理解に苦しむところ) よって sed の実装に依存しない (移植性 (portability) を考慮した) sed スクリプトを書くには GNU sed などの特殊な実装を考慮した BRE を記述する必要があります。 結局どうすればいいの? =========== 「`${fuga}` に含まれるスペースなどを維持する」、「sed で先頭の 1 文字以上のスペースを削除する」(移植性を考慮する) でよければ、スクリプトは次のようになります。 ``` #!/bin/bash fuga=" string" echo "${fuga}" | sed -e 's|^ *||' ```