1965


sed コマンドで以下が動きません。  
環境: Mac OS X の Yosemite  
目的: `hello` から先を `X` に置き換え、`helloX` を得たい。

[code]

    echo "helloddkkdddd" | sed -e "s/hello.\+/X/g"
    
[/code]

よろしくお願いします。


CC BY-SA 3.0
2014-12-18T03:14:26.710
1964
2015-08-29T04:14:54.070
2014-12-18T08:46:35.800
898
4874
question
sed 正規表現
sedコマンド 正規表現 +の扱い


グループ化をつかって以下の様に

[code]

    echo "helloddkkdddd" | sed -e "s/\(hello\).\+/\1X/g"
    
[/code]

とすれば

[code]

    helloX
    
[/code]

となります。

簡単な説明としては

`\\(...\\)`で括られた部分がグループとして扱われ、`\1` を使って最初に登場したグループのマッチ結果を出力することができます。


CC BY-SA 3.0
2014-12-18T03:19:47.353
1965
2014-12-18T11:37:56.970
2014-12-18T11:37:56.970
76
728
1964
answer


Macのsedだと+が使えないか、別の表現が必要なようです。

[code]

    $ echo "helloddkkdddd" | gsed -e "s/hello..*/X/g"
    X
    
[/code]

とやるか、brewをお使いでしたら、

[code]

    $ brew install coreutils
    
[/code]

としてGNUのsed（gsed）をインストールすると+が使えます。

[code]

    $ echo "helloddkkdddd" | gsed -e "s/hello.\+/X/g"
    X
    
[/code]

-r オプションを指定すれば、バックスラッシュでエスケープする必要はありません。
[code]

    $ echo "helloddkkdddd" | gsed -r -e "s/hello.+/X/g"
    X
    
[/code]

出力が

[code]

    $ echo "helloddkkdddd" | sed 
    helloxxxxxxxx
    
[/code]

というものなら、ちょっと悩みますが、とりあえずawkを使うズルを一つ提示しておきます。

[code]

    $ echo "helloddkkdddd" | sed 's/hello\(.*\)/hello \1/' | awk '{gsub(/./,"X",$2);print}' | sed 's/ //'
    helloXXXXXXXX
    
[/code]


CC BY-SA 3.0
2014-12-18T03:39:44.340
1970
2014-12-18T11:06:01.060
2014-12-18T11:06:01.060
4480
1964
answer


Mac ではなく Linux の文章ですが・・・

  * <http://linuxjm.sourceforge.jp/html/LDP_man-pages/man7/regex.7.html>

> 古い ("基本") 正規表現は、いくつかの点において異なる。 '|', '+', and '?' は通常の文字となる。
> 対応する機能は存在しない。繰り返し指定の区切りは "\{" および "\}" となる。'{' と '}' は、 単独では通常の文字として扱われる。
> 部分正規表現をネストする括弧は "\(" および "\)" となり、 '(' と ')' は単独では通常の文字となる。 '^' は正規表現の先頭か、
> 括弧でくくられた部分表現の先頭(!)を除いて通常の文字となる。 '$' は正規表現の末尾か、
> 括弧でくくられた部分正規表現の末尾(!)を除いて通常の文字となる。 '*' は、正規表現の先頭か、
> 括弧でくくられた部分文字列の先頭に置かれた場合は通常の文字となる ('^') が前置されていてもよい)。

`|`、`+`、`?` は存在せず、`(`、`)`、`{`、`}` はそのままだと単なる文字として認識されるため
`\\(`、`\\)`、`\\{`、`\\}` のようなエスケープが必要、とのことです。

たしかに `(` や `)` が正規表現のメタ文字ではなく、単なる文字として解釈されています。

[code]

    $ echo '(())' | sed 's/()/^^/'
    (^^)
    
[/code]


CC BY-SA 3.0
2014-12-18T05:29:08.747
1986
2014-12-18T05:29:08.747
2494
1964
answer


sed で利用できる正規表現は拡張正規表現ではありません。  
GNU sed であればバックスラッシュ `\` を前に付与し `\\+` のようにすることで拡張正規表現のパターンを書けますが、GNU sed 以外の
sed 実装では使えません。

よって、どのような sed でも利用できるコマンドラインは次のようになります:

[code]

    $ echo "helloddkkdddd" | sed -e "s/\(hello\)..*/\1X/g"
    
[/code]

もしくは繰り返し回数指定の `\\{MIN,MAX\\}` を利用して次のようになります:

[code]

    $ echo "helloddkkdddd" | sed -e "s/\(hello\).\{1,\}/\1X/g"
    
[/code]

GNU sed 依存でよければ次のようになります:

[code]

    $ echo "helloddkkdddd" | sed -e "s/\(hello\).\+/\1X/g"
    
[/code]

Mac OS X や FreeBSDの sed であれば `-E` オプションを付けることで拡張正規表現が使えます。  
よって次のようになります。

[code]

    $ echo "helloddkkdddd" | sed -E -e "s/(hello).+/\1X/g"
    
[/code]

GNU sed も `-r` オプションで直接(`\`なしで)拡張正規表現が使えます。  
また、FreeBSD の sed にも GNU sed 互換用の `-r` オプションがあります。  
よって、GNU sed もしくは FreeBSD sed では次のように書けます。

[code]

    $ echo "helloddkkdddd" | sed -r -e "s/(hello).+/\1X/g"
    
[/code]


CC BY-SA 3.0
2014-12-18T13:47:21.647
2047
2015-08-29T04:14:54.070
2015-08-29T04:14:54.070
3061
3061
1964
answer