MOテクノロジー

技術をメモしていくブログ

sedの使い方忘れないように

sedを使いこなしたいと思いつつ、多機能すぎてついつい忘れてしまう。
基本の使い方のチートシート的な。使っているのはMacの標準で入っているBSD系のsed

# パイプつなぎ
~ $ echo It is sunny today. | sed 's/sunny/rainy/g'
It is rainy today.

# 複数つなげる時は -e
~ $ echo It is sunny today. | sed -e 's/sunny/rainy/g' -e 's/rainy/cloudy/g'
It is cloudy today.

# ファイルをインプットとする
~ $ cat weather.txt
It is sunny today.
~ $ sed -e 's/sunny/rainy/g' weather.txt
It is rainy today.

ちょっと便利な使い方
特定の文字列が出てきた時、それを抽出したい。
例えば、uniqueIDという文字列が出てきた時、それに続くIDを取得したいケース。

  • 前提1:行によって要素数が異なるため、単純にカンマ区切りで抽出とかはできない
  • 前提2:uniqueIDは10桁の固定とし、1行内にuniqueIDは1回しか出てこないとする
# パイプつなぎ
~ $ echo \"time:2020-08-01\",\"uniqueID\":\"ABCDEFGHIJ\",\"name\":\"hoge\" | sed -e 's/^.*uniqueID":"\(.\{10\}\).*$/\"uniqueID\":\"\1\"/'
"uniqueID":"ABCDEFGHIJ"

# ファイルをインプットとする(マッチしないする行も出力してしまうので最後にgrepしている。grepせんでもsedだけでできそうな気もするが...)
~ $ cat log
"time:2020-08-01","uniqueID":"ABCDEFGHIJ","name":"hoge"
"time:2020-08-01","wanwan":"inu","nyannyan":"neko"
"time:2020-08-01","uniqueID":"WANNYANWAN","wanwan":"inu"
~ $ sed -e 's/^.*uniqueID":"\(.\{10\}\).*$/\"uniqueID\":\"\1\"/' log | grep uniqueID
"uniqueID":"ABCDEFGHIJ"
"uniqueID":"WANNYANWAN"

# やってること
# "uniqueID:"という文字列が出てきた時、その後に続く10文字を取得する
# "uniqueID:"という文字列以降全てを、"uniqueID:" + 取得した10文字に置換する

()でグループ化して\1でマッチしてる部分を取得しているとことが肝。例えばこんなふうに使える。

# グループに一致した値が`\1`に入る
~ $ echo abcdefghij | sed -e 's/^.*def\(.\{1\}\).*$/\1/g'
g

# グループが複数ある場合、採番が振られる
~ $ echo abcdefghij | sed -e 's/^.*def\(.\{1\}\)\(.\{1\}\).*$/\1 \2/g'
g h

これだけ覚えていればいろいろできそうだぞ(できない)