echoコマンドのブレース展開で便利に連番の文字を作る

中括弧(`{}`)を使用して複数の文字列を生成する機能を「ブレース展開」というそうです。
```bash
# 連番を作りたい
$ echo {0..31}
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

# AからZまでの羅列を作りたい
$ echo {A..Z}
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z

# ネストもできる
$ echo hoge{A{1..5},B{6..10}}
hogeA1 hogeA2 hogeA3 hogeA4 hogeA5 hogeB6 hogeB7 hogeB8 hogeB9 hogeB10
```

# 活用事例
これまで、知ってはいたけれどあまり使わずやり方も忘れていたのですが、ふと「書くの面倒くさいな」と思うSQLをこの「ブレース展開」で作ったところ大変便利でした。

## (SQL)カラム名が連番のカラムでLIKE検索するWHERE句を作る
- 環境 : GNU bash, version 4.4.23(2)-release (x86_64-pc-msys)

「name1_kana」というカラムが「1~13」まであるテーブルで、いずれかに「pon」が含まれるレコードを検索する場合のWHERE句を作る

- ポイント
    1. 最後に「OR」が余分に出力されるので手動で削除して使う
    1. 繰り返し部分を「"」で囲う

```bash
$ echo WHERE name{1..13}"_kana LIKE '%pon%' OR"
WHERE name1_kana LIKE '%pon%' OR name2_kana LIKE '%pon%' OR name3_kana LIKE '%pon%' OR name4_kana LIKE '%pon%' OR name5_kana LIKE '%pon%' OR name6_kana LIKE '%pon%' OR name7_kana LIKE '%pon%' OR name8_kana LIKE '%pon%' OR name9_kana LIKE '%pon%' OR name10_kana LIKE '%pon%' OR name11_kana LIKE '%pon%' OR name12_kana LIKE '%pon%' OR name13_kana LIKE '%pon%' OR

# 失敗事例:「"」がなくてLIKE以降が繰り返されない
$ echo WHERE name{1..13}_kana LIKE '%pon%' OR
WHERE name1_kana name2_kana name3_kana name4_kana name5_kana name6_kana name7_kana name8_kana name9_kana name10_kana name11_kana name12_kana name13_kana LIKE %pon% OR
```

## (SQL)同じカラムで複数文字をLIKE検索するSQLを作る
- 環境 : GNU bash, version 4.4.23(2)-release (x86_64-pc-msys)

「column」というカラムに複数の任意の文字いずれかが含まれるレコードを検索する場合のSQLを作る
- ポイント
    1. 最後に「OR」が余分に出力されるので手動で削除して使う
    1. 繰り返し部分は前後に別々に「"」で囲う
    1. SELECTでよく使う「*」はエスケープする

```bash
$ echo SELECT \* FROM table WHERE "column LIKE '%"{←,→,↓,↑,♪,☆,★,♂,♥,–}"%' OR "
SELECT * FROM table WHERE column LIKE '%←%' OR  column LIKE '%→%' OR  column LIKE '%↓%' OR  column LIKE '%↑%' OR  column LIKE '%♪%' OR  column LIKE '%☆%' OR  column LIKE '%★%' OR  column LIKE '%♂%' OR  column LIKE '%♥%' OR  column LIKE '%–%' OR 

# 失敗事例:「"」がなくて展開されない
$ echo SELECT \* FROM table WHERE column LIKE '%{←,→,↓,↑,♪,☆,★,♂,♥,–}%' OR
SELECT * FROM table WHERE column LIKE %{←,→,↓,↑,♪,☆,★,♂,♥,–}% OR
# 失敗事例:繰り返し部分を1セットの「"」で囲んで展開されない
$ echo SELECT \* FROM table WHERE "column LIKE '%{←,→,↓,↑,♪,☆,★,♂,♥,–}%' OR "
SELECT * FROM table WHERE column LIKE '%{←,→,↓,↑,♪,☆,★,♂,♥,–}%' OR
# 失敗事例:「*」をエスケープしないのでカレントディレクトリのファイル名が出力される
$ echo SELECT * FROM table WHERE "column LIKE '%"{←,→,↓,↑,♪,☆,★,♂,♥,–}"%' OR "
SELECT file.txt zip_file.zip FROM table WHERE column LIKE '%←%' OR  column LIKE '%→%' OR  column LIKE '%↓%' OR  column LIKE '%↑%' OR  column LIKE '%♪%' OR  column LIKE '%☆%' OR  column LIKE '%★%' OR  column LIKE '%♂%' OR  column LIKE '%♥%' OR  column LIKE '%–%' OR 
```


## (SQL)同じ正規表現で複数カラムを検索するSQLを作る
- 環境 : GNU bash, version 4.4.23(2)-release (x86_64-pc-msys)

MySQLにはREGEXP演算子があり、正規表現での検索ができる。

> expr REGEXP pat, expr RLIKE pat
> 文字列 expr がパターン pat で指定された正規表現と一致する場合は 1 を返し、一致しない場合は 0 を返します。 expr または pat が NULL の場合、戻り値は NULL です。
> [MySQL :: MySQL 8.0 リファレンスマニュアル :: 12.8.2 正規表現](https://dev.mysql.com/doc/refman/8.0/ja/regexp.html#operator_regexp)

例えば、「column」列の値が「半角スペースで始まる」を書くと`column regexp '^ '`となりる。
複数の正規表現での検索もできて、「column」列の値が「全半角スペースで始まるまたは終わる」を書くと`column regexp '^( |　)|( |　)$'`となる。

しかし、複数のカラムで「全半角スペースで始まるまたは終わる」を手動で書くのは面倒くさいのでechoを活用してSQLを作る。

```sql
$ echo SELECT \* FROM table WHERE {name,name_kana,uji,uji_kana,hoge,fuga}" REGEXP '^( |　)|( |　)$' OR"
SELECT * FROM table WHERE name REGEXP '^( |　)|( |　)$' OR name_kana REGEXP '^( |　)|( |　)$' OR uji REGEXP '^( |　)|( |　)$' OR uji_kana REGEXP '^( |　)|( |　)$' OR hoge REGEXP '^( |　)|( |　)$' OR fuga REGEXP '^( |　)|( |　)$' OR
```

## (SQL)プレース展開した文字を複数個所で使用する

「name1」というカラムが「1~13」まであるテーブルで、値があったら「name」を出力してなければ「null」を出力すcase文を「name1~13」全部で作る

- ポイント
    - awk内で `$i` を使うと、awk自体の変数として解釈され値が展開されないので、`i`を直接文字列として使うようにした
    - ダブルクォートの中でシェルの変数を展開しないように、`"name\"i\""`のように`i`を展開しない形で記述

```bash
$ eval "echo {1..13} | awk '{for(i=1;i<=NF;i++) print \"(case when name\"i\" is not null then name\"i\" else null end) as 名前\"i\",\"}'"
(case when name1 is not null then name1 else null end) as 名前1,
(case when name2 is not null then name2 else null end) as 名前2,
(case when name3 is not null then name3 else null end) as 名前3,
(case when name4 is not null then name4 else null end) as 名前4,
(case when name5 is not null then name5 else null end) as 名前5,
(case when name6 is not null then name6 else null end) as 名前6,
(case when name7 is not null then name7 else null end) as 名前7,
(case when name8 is not null then name8 else null end) as 名前8,
(case when name9 is not null then name9 else null end) as 名前9,
(case when name10 is not null then name10 else null end) as 名前10,
(case when name11 is not null then name11 else null end) as 名前11,
(case when name12 is not null then name12 else null end) as 名前12,
(case when name13 is not null then name13 else null end) as 名前13,
```