\iでSQLファイルを読み込んで実行する

psqlの\iメタコマンドは、指定したファイルの内容を読み込んで実行する。psql -fと似ているが、実行中のセッション内から他のスクリプトを呼び出せる点が異なる。

testdb=# \i main.sql
loading main.sql
loaded child.sql
 count
-------
     2
(1 row)

main.sqlの中で別のファイルをさらに\iで読み込むこともできる。

-- main.sql
\echo 'loading main.sql'
\i sub/child.sql

\iの相対パスはpsqlのカレントディレクトリ基準

\iに相対パスを指定した場合、その時点でpsqlプロセスが実行されているカレントディレクトリを基準に解決される。スクリプトファイル自身の場所は基準にならない。

/tmp/psql-io-testディレクトリの外からmain.sqlを指定して実行すると、main.sql内の\i sub/child.sqlが失敗する。

$ psql -d testdb -f /tmp/psql-io-test/main.sql
loading main.sql
psql:/tmp/psql-io-test/main.sql:2: error: sub/child.sql: No such file or directory

main.sql自体は絶対パスで指定できているのに、内部の\i sub/child.sqlはカレントディレクトリ(/tmp/psql-io-test以外の場所)からの相対パスとして解釈され、見つからない。

\irはスクリプト自身の場所を基準にする

\ir\iとほぼ同じだが、相対パスをカレントディレクトリではなく、実行中のスクリプトファイル自身が置かれているディレクトリを基準に解決する。

-- main-ir.sql
\echo 'loading main-ir.sql'
\ir sub/child.sql
$ cd /tmp && psql -d testdb -f /tmp/psql-io-test/main-ir.sql
loading main-ir.sql
loaded child.sql
 count
-------
     2
(1 row)

カレントディレクトリが/tmpであっても、main-ir.sqlと同じディレクトリにあるsub/child.sqlを正しく見つけて読み込む。複数のSQLファイルを分割して相互に\i/\irで読み込ませる場合、実行時のカレントディレクトリに依存させたくないなら\irを使う。

\oでクエリ出力をファイルへリダイレクトする

\oにファイル名を指定すると、以降のクエリ結果を画面の代わりにそのファイルへ書き込む。引数なしで実行すると画面表示に戻る。

testdb=# \o /tmp/output.txt
testdb=# SELECT * FROM users;
testdb=# \o
testdb=# \echo 'back to screen'
back to screen
testdb=# SELECT count(*) FROM users;
 count
-------
     2
(1 row)
$ cat /tmp/output.txt
 id | name  |       email
----+-------+-------------------
  1 | alice | alice@example.com
  2 | bob   | bob@example.com
(2 rows)

\oが有効な間は、クエリ結果だけでなく\dなどのメタコマンドの出力も同じファイルへ書き込まれる。

\echoと\qechoの違い

\echoはテキストを常に標準出力(画面)へ表示する。\qecho\oで指定した現在のクエリ出力先(画面またはファイル)へ表示する。

\oでファイルへリダイレクトした状態で両方を実行すると、書き込まれる先が異なる。

testdb=# \o /tmp/qecho-test.txt
testdb=# \qecho 'this goes to file'
testdb=# \echo 'does this also go to file?'
does this also go to file?
testdb=# \o
$ cat /tmp/qecho-test.txt
this goes to file

\echoのメッセージは画面にそのまま表示され、\qechoのメッセージだけがファイルに書き込まれている。スクリプトの進捗をユーザー向けに画面へ出力したいときは\echo、クエリ結果と同じ場所に見出しやコメントを混ぜて出力したいときは\qechoを使う。

具体例: スクリプトの実行結果をログに残しつつ進捗も表示する

バッチ処理用のSQLスクリプトで、実行結果はファイルに保存しつつ、進捗メッセージは画面に出したい場合、\o\echo/\qechoを組み合わせる。

-- batch.sql
\echo 'starting batch...'
\o /tmp/batch-result.txt
\qecho '=== user counts ==='
SELECT count(*) FROM users;
\o
\echo 'batch finished'
$ psql -d testdb -f batch.sql
starting batch...
batch finished
$ cat /tmp/batch-result.txt
=== user counts ===
 count
-------
     2
(1 row)

画面には進捗の2行だけが表示され、クエリ結果と見出しはファイルにまとまって記録される。

参考