正規表現 & sed & awk

- `echo` がエスケープ文字 (`\n` など) を解釈しない場合は `-e` オプションをつける

## POSIX 正規表現

### `grep` のパターン、および `sed 's/A/B/'` の `A` (置換対象) などで使えるもの

|                      名前                       |                                     基本正規表現<br>(BRE)                                      |                                  拡張正規表現<br>(ERE)                                   |                                                                                                    対象文字列 (表現は ERE)                                                                                                    |           例 (ERE)            |
| :---------------------------------------------: | :--------------------------------------------------------------------------------------------: | :--------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :---------------------------: |
|       キャラクタリスト<br>Character list        |                                            `[` `]`                                             |                                          (同じ)                                          |                                                                          囲まれた文字のどれか<br>`-` で連続した範囲を指定<br>`^` はそれ以外とマッチ                                                                           |   [ABC]<br>[0-9]<br>[^0-9]    |
|       キャラクタクラス<br>Character class       |                                           `[:` `:]`                                            |                                          (同じ)                                          |                                                                                                     特定の文字集合を表す                                                                                                      | [\[:alpha:]]<br>[\^[:digit:]] |
|        照合シンボル<br>Collating symbol         |                                           `[.` `.]`                                            |                                          (同じ)                                          |                                                                                                  複数文字を 1 文字として扱う                                                                                                  |          [\[.hoge.]]          |
|         等価クラス<br>Equivalence class         |                                           `[=` `=]`                                            |                                          (同じ)                                          |                                                                                                等価に扱う文字の集合を表す<br>                                                                                                 |     [\[=e=]]<br>[\[=u=]]      |
|                  ドット<br>Dot                  |                                              `.`                                               |                                          (同じ)                                          |                                                                                                         任意の 1 文字                                                                                                         |               .               |
|     エスケープ文字<br>Escaped<br>character      |                                       <code>\\_x_</code>                                       |                                          (同じ)                                          |                                                                                                メタ文字 <code>_x_</code> 自身                                                                                                 |              \\.              |
|     先頭マッチ・<br>末尾マッチ<br>Anchoring     |                                           `^`<br>`$`                                           |                                          (同じ)                                          |                                                                               行の先頭 (`^`)・末尾 (`$`)<br>(先頭・末尾以外では通常文字となる)                                                                                |          ^#<br>\\.\$          |
| 繰返し指定子<br>Single-character<br>duplication | `*`<br><br><br><code>\\{_n_\\}</code><br><code>\\{_n_,\\}</code><br><code>\\{_n_,_m_\\}</code> | `*`<br>`+`<br>`?`<br><code>{_n_}</code><br><code>{_n_,}</code><br><code>{_n_,_m_}</code> | `*` は `{0,}` と同じ<br>`+` は `{1,}` と同じ<br>`?` は `{0,1}` と同じ<br><code>{_n_}</code> は直前の文字が _n_ 文字連続<br><code>{_n_,}</code> は _n_ 文字以上連続<br><code>{_n_,_m_}</code> は _n_ 文字以上 _m_ 文字以下連続 |         .\*<br>a{3,5}         |
|     包括指定子・<br>後方参照子<br>Grouping      |                                `\(` `\)`<br><code>\\_n_</code>                                 |                              `(` `)`<br><code>\\_n_</code>                               |                                                                            `()` でマッチの塊を扱う<br><code>\\_n_</code> は _n_ 番目の `()` に対応                                                                            |        ([a-z]\*) \1\*         |
|           論理和指定子<br>Alternation           |                              <code>\\&#124;</code><br>(GNU 拡張)                               |                                   <code>&#124;</code>                                    |                                                                                           <code>&#124;</code> の左または右の文字列                                                                                            |        ^ABC&#124;DEF\$        |

### `sed s/A/B/` の `B` (置換後の文字列) で使えるもの

|      名前      |     BRE / ERE      |          置換される文字列          | 例  |
| :------------: | :----------------: | :--------------------------------: | :-: |
|   後方参照子   | <code>\\_n_</code> | _n_ 番目の `()` でマッチした文字列 | \1  |
|   全体マッチ   |        `&`         |        マッチした文字列全体        |  &  |
| エスケープ文字 | <code>\\_x_</code> |   メタ文字 <code>_x_</code> 自身   | \\& |

## `grep` コマンド

```bash:使い方
$ grep [options] 'pattern' input_file
```

- パターンは正規表現
  - デフォルトは基本正規表現 (BRE)、オプションで `-E` を指定すると拡張正規表現 (ERE)
  - メタ文字 (`|` など) を扱う場合はクオートで囲む
- `-i` オプションは大文字・小文字の区別を無視する
- `-v` オプションはマッチしなかった行を表示する

## `sed` コマンド

```bash:使い方
$ sed [options] 'pattern[;pattern...]' input_file
```

- パターンは `"` で囲むと特殊記号がシェルに展開されてしまうので、`'` で囲むようにする
- `sed: RE error: illegal byte sequence` となったら `$ export LANG=C` でロケールを変更する
- 正規表現はデフォルトで BRE、`-E` か `-r` オプションで ERE
- `-n` オプションがあると、修正された行だけを出力する

### パターン `pattern` の前半部分 (処理する行の指定)

|                                        記法                                         |                                              処理される行                                               |            例             |
| :---------------------------------------------------------------------------------: | :-----------------------------------------------------------------------------------------------------: | :-----------------------: |
|                                  <code>_n_</code>                                   |                                    _n_ 行目<br>`$` は最後の行を表す                                     |             1             |
|                                <code>_n_,_m_</code>                                 |                                        _n_ 行目から _m_ 行目<br>                                        |            1,3            |
|                                <code>_n_~_m_</code>                                 |                                         _n_ 行目から _m_ 行ごと                                         | 3~2<br>(3, 5, 7, ...行目) |
|                                <code>_n_,~_m_</code>                                |                                    _n_ 行目から次の _m_ の倍数行まで                                    |  5,~4<br>(5 から 8 行目)  |
| <code>/_regexp_/</code><br><code>/_regexp_/!</code><br><code>/_re1_/,/_re2_/</code> | 正規表現 _regexp_ とマッチする行<br>マッチしない行<br>_re1_ にマッチした行から _re2_ にマッチした行まで |          /hoge/           |

### パターン `pattern` の後半部分 (処理の指定)

|                記法                |                                                                                        処理                                                                                        |      例      |
| :--------------------------------: | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | :----------: |
|                `=`                 |                                                            行番号を前の行に表示<br>(`-n` オプションで行番号だけを抽出)                                                             |    /dog/=    |
|       <code>a _word_</code>        |                                                                            文字列 _word_ を次の行に追加                                                                            | /dog/a hoge  |
|       <code>i _word_</code>        |                                                                            文字列 _word_ を前の行に追加                                                                            |  1,2i hoge   |
|                `q`                 |                                                                                処理をそこで終了する                                                                                |    /dog/q    |
|       <code>c _word_</code>        |                                                        選択された行を指定された文字列を置換<br>(word には`\n`を含んでよい)                                                         | /dog/c hoge  |
|                `d`                 |                                                                                      行を削除                                                                                      |      2d      |
|                `p`                 |                                                                 行を表示<br>(`-n`オプションで条件に合う行だけ抽出)                                                                 |      2p      | cat\ndog\ndog\nfish |
| <code>s/_regexp_/_replace_/</code> | 正規表現 _regexp_ とマッチする文字列を _replace_ に置換<br>デリミタは `/` 以外でもよい (例: <code>&#124;</code> や `;`)<br>デフォルトでは最初のマッチだけ処理<br>末尾に `g` があると全マッチを処理 |    s/N//g    |
| <code>y/_target_/_replace_/</code> |                                                 _target_ の各文字を _replace_ の各文字に変換<br>(両者は同じ長さでなければならない)                                                 | y/acgt/ACGT/ |

## `gsed` コマンド

- (BSD の) `sed`では置換のパターン中に含まれる (メタ文字以外の) エスケープ文字を正しく認識できないので、そのような場合は GNU 拡張の `gsed` を使う
  - `$ echo -e "\t" | gsed 's/\t/OK/g'`
  - ただし、改行については次のやり方でないとダメ
    - `$ echo -e "\n" | gsed ':loop; N; $!b loop; ;s/\n/OK/g'`
- 他にも、`-i`(`--in-place`) オプションを使うことで、指定されたファイルを開いて置換して保存してくれる
  - `$ gsed -i "s/hoge/huga/g" *.txt` のような書き方が可能になる
  - BSD だと `for` でファイル名をそれぞれ展開して処理してからリダイレクトしないとダメ

## `awk` コマンド

```bash:使い方
$ awk [option] 'pattern{action}[pattern{action}...]' input_file
```

- `sed` と同様にプログラム (ルールの集合) は `'` で囲むようにする

### 組み込み変数

|  組み込み変数名  |                                  説明                                   | デフォルト値 |
| :--------------: | :---------------------------------------------------------------------: | :----------: |
|       `RS`       |                  レコード (読み込みの単位) セパレータ                   |     改行     |
|       `FS`       | フィールド (レコードの要素の単位) セパレータ<br>`-F` オプションで変更可 |   スペース   |
|       `NR`       |                           現在のレコード番号                            |              |
|       `NF`       |                    現在のレコードが持つフィールド数                     |              |
|       `$0`       |                           現在のレコード全体                            |              |
| `$1`, ..., `$NF` |                 現在のレコードの各フィールド (代入も可)                 |

### パターン `pattern`

|                                              `pattern`                                              |                                                     アクションが実行される条件                                                      |                               ルールの例                                |
| :-------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------------------------------------------------------------------: | :---------------------------------------------------------------------: |
|                                           (パターンなし)                                            |                                                              常に実行                                                               |                              {print \$NF}                               |
|                                               `BEGIN`                                               |                                                      先頭行を読み込む前に実行                                                       |                        BEGIN {print "Not Read"}                         |
|                                                `END`                                                |                                                   最終行の処理が終わった後に実行                                                    |                       END {print "Already Read"}                        |
| <code>/_regexpr_/</code><br><code>_expr_ ~ /_regexpr_/</code><br><code>_expr_ !~ /_regexpr_/</code> | レコード全体が _regexpr_ にマッチしたら実行<br>_expr_ が _regexpr_ にマッチしたら実行<br>_expr_ が _regexpr_ にマッチしなければ実行 | /hoge/ {print \$1}<br>\$1 ~ /^>/ {print \$0}<br>\$1 !~ /^>/ {print \$0} |
|                                         <code>_cond_</code>                                         |                                                    条件式 _cond_ が真のとき実行                                                     |                   length(\$0) == 0 {print "Nothing"}                    |

### アクション `action` で使用可能な関数・構文の一例

|                        `action`                         |                                                                                            説明                                                                                            |
| :-----------------------------------------------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: |
|              <code>_word1_ _word2_</code>               |                                                                            文字列・変数の連結<br>空白を挟むだけ                                                                            |
| <code>print _word_</code><br><code>printf _word_</code> |                                                                  文字列を表示<br>`print` は改行あり、`printf` は改行なし                                                                   |
|                      `printf(...)`                      |                                                                             C の `printf` 関数と同じように使う                                                                             |
|               <code>index(_s_,_t_)</code>               |                                                                   文字列 _s_ で文字列 _t_ が現れる最初の位置を返す                                                                   |
|                   <code>length(_s_)</code>                    |                                                                          _s_ を文字列と見なしてその長さを返す                                                                           |
|           <code>substr(_s_,_b_)</code><br><code>substr(_s_,_b_,_l_)</code>          |                                                           _s_ の _b_ 番目の文字以降を返す<br>_s_ の _b_ 番目から始まる長さ _l_ の文字列を返す                                                           |
|       <code>tolower(_s_)</code><br><code>toupper(_s_)</code>        |                                                                 _s_ 中の大[小]文字を小[大]文字にした文字列を返す                                                                  |
|              <code>gsub(_regexpr_,_word_,_s_)</code>              | _regexpr_ とマッチする _s_ 中の文字列を _word_ に置換<br>_word_ を `&` にするとマッチした文字列になる<br>_s_ を省略すると \$0 に対して行われる<br>返り値はマッチした個数 |
|                     `for(...){...}`                     |                                                             C と同じか、`for(i in array)` のようにもできる                                                             |
|                `if(...){...} else{...}`                 |                                                                                C と同じ方                                                                                |
|                    (アクションなし)                     |                                                                           `{print $0}` と同じ挙動 (= 条件に合う行の抽出)                                                                           |

## 例

[Steve Turner の bioinformatics におけるワンライナー集](https://github.com/stephenturner/oneliners)には `sed`, `awk` 以外にもいろいろなコマンドの例が載っている。

- multi-fasta をそれぞれの fasta に分割
  - `awk '/^>/{s=++d".fa"} {print > s}' multi.fa`
- fasta 中の各 sequence の名前とその長さを表示
  - `awk 'BEGIN {c=-1;} $0 ~ ">" {if(c>=0){print c}; c=0; printf substr($0,2,100) "\t";} $0 !~ ">" {c+=length($0);} END {print c;}' file.fa`
- fastq を fasta に変換
  - `sed -n '1~4s/^@/>/p; 2~4p' file.fq > file.fa`
- 指定された範囲の行を表示
  - `awk 'NR>=20&&NR<=80' input.txt`
- 指定された列に操作を施して最後の列に追加
  - `awk '{print $0,$2+$3}' input.txt`
- fastq 中の read の平均長を求める
  - `awk 'NR%4==2{sum+=length(\$0)}END{print sum/(NR/4)}' file.fq`