なか日記

一度きりの人生、楽しく生きよう。

PowerShellでちょっと遊んでみた

いいタイトルが思いつかなくてごめんなさい。

経緯

ちょっとお仕事でこんなシェル*1を作ることになりまして、

#!/bin/sh

sqlplus test/test@orcl << EOF
select * from aaaa
where id = ${id}
and name = ${name}
;
EOF

作る部分は << EOF から EOF の間のSQLなんですが、そのままシェルの中に書いてたらSQLを実行させながら作れないですよね。というわけで、ちょっと遊んでみました。

やりたいこと

  • 変数部分は全てリテラルにして、SQLを実行しながら単体で作りたい
  • SQLができたらシェルに組み込みたい
  • シェルに組み込んだら、変数部分は復活させたい

ちょこっとやってみた

そうだ、PowerShellで遊んでみよう!もちろん、業務時間に?
というわけで、以下のようなファイルを同一ディレクトリ内に用意します。

テンプレート(test.tpl

シェルのひな形です。
#INSERT となってる部分が<>内のファイル内容で置き換えられるというわけですね。

#!/bin/sh

sqlplus test/test@orcl << EOF
#INSERT<test_01.sql>
EOF
SQLファイル(test_01.sql

メインのロジック部分。
「/**/」で囲まれた部分が、「xxx」に置き換えられるので、SQLを組み立てるときはリテラルで実行しながら作業できます。

select * from hoge
where id = /*<REPLACE ${id} */ 999 /*>*/
and name = /*<REPLACE ${name} */ 'nakaji' /*>*/
;
PowerShellスクリプト(test.ps1)

以下の内容でスクリプトを作成しました。エラー処理はざるです。
引数にテンプレートファイルを指定して実行すると、標準出力に結果が出力されるのでリダイレクトするなりしてファイルに保存します。

Param([String]$templateName)

function InsertFile([String]$directory, [String]$fileName)
{
    $insertFileName = Join-Path $directory $fileName
    if (-not(Test-Path $insertFileName)) {
        Write-Error ("ファイルが存在しません:" + $insertFileName)
        return;
    }
    Get-Content $insertFileName
}

Get-Content $templateName | 
%{
    # 「#<INSERT hoge>」の部分を「hoge」のファイルの内容に差し替える
    if ($_ -match "^#INSERT<(.+)>.*") {
        #Split-Path $templateName -Parent | InsertFile($_, $matches[1])
        $directory = Split-Path $templateName -Parent
        $buf = InsertFile $directory $matches[1]
        $buf
    } else {
        $_
    }
} | %{
        # 「/*<REPLACE hoge */ piyo /*>*/」 を 「hoge」に置換
        $_ -replace '/\*<REPLACE\s+(.+)\s+\*/\s.+\s/\*>\*/', '$1'
    }

実行

PS D:\> .\test.ps1 .\test.tpl
#!/bin/sh

sqlplus test/test@orcl << EOF
select * from aaaa
where id = ${id}
and name = ${name}
;
EOF

よっしゃこれでちょっと楽ができる!と思ったら、その前にそのお仕事は終わってましたとさ。orz

*1:実際はもうちょっと複雑なんだよ!本当だよ!