やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

SQLite3学習 入出力関数(fsdir, readfile, writefile, edit)

 edit関数で列データを任意アプリで編集できる!

成果物

一覧

SQL関数 概要
fsdir() 指定したパスを再帰的に解析してディレクトリやファイルの情報をもったテーブルを返す
readfile() 指定したパスのファイル内容を返す
writefile() 指定したパスに指定した内容を書き込む
edit() 指定したデータを指定したアプリで編集する
SELECT * from fsdir('/tmp/work/');
SELECT readfile('/tmp/work/a.txt');
SELECT writefile('/tmp/work/a.txt', '内容');
SELECT edit('内容', 'vim');

テスト用ファイル作成

 ターミナルで以下コマンド実行。

cd /tmp/work
mkdir test_dir/
cd test_dir/
echo -e "あああ\nいいい" > test.txt
sqlite3

fsdir()

 指定したディレクトリ配下をテーブルで一覧する。

.headers on
select * from fsdir('/tmp/work/test_dir/');

 パスや内容などが得られる。

name|mode|mtime|data
/tmp/work/test_dir/|16877|1565767985|
/tmp/work/test_dir//test.txt|33188|1565767985|あああ
いいい
  • nameはフルパス
    • なぜ//test.txtとスラッシュが2つあるのか謎
  • modeって何? パーミッションと違うの?
  • mtimeはたぶん最終更新日時。生成日時などがないのはファイルシステムごとに仕様が微妙に違うからか?
  • dataはファイルの中身

readfile()

 指定したファイルの内容を返す。以下のどちらでもOK。

select readfile('/tmp/work/test_dir//test.txt');
select readfile('/tmp/work/test_dir/test.txt');
あああ
いいい

 読込後のデータにはなぜか末尾に\nが付与されてしまうためrtrim(readfile(), x'0A')とすることで省く。

select rtrim(readfile('/tmp/work/test_dir//test.txt'),x'0A');
あああ
いいい

writefile()

 ファイルに書き込む。

 ブログ用テーブルを作る。

create table posts(id integer primary key, title text, body text);

 ブログの内容を挿入する。

insert into posts values(1, 'タイトル', '# 見出し

* 項目A
* 項目B
');

 ファイル出力する。

select writefile('/tmp/work/' || title || '.md', body) from posts WHERE id=1;

 以下のファイルが出力される。

/tmp/work/タイトル.md

# 見出し

* 項目A
* 項目B

edit()

 ブログ用テーブルを作る。

create table posts(id integer primary key, title text, body text);

 内容が空のレコードを作る。

insert into posts values(1, 'タイトル', '');

 内容をエディタで編集させる。

UPDATE posts SET body=edit(body, 'vim') WHERE id=1;

 vimが起動するので以下のように編集する。

# vimで編集

* すごい
* かっこいい

 :wqで上書き終了。

 エディタで編集が完了したらSQLite3対話モード画面に戻るので、テーブルをみてみる。

select * from posts;
1|タイトル|# vimで編集

* すごい
* かっこいい

 編集したデータが入っている! これでSQLite3のテーブルデータをアプリケーションで編集できる! これだよ、これがやりたかった。

  • edit()の第二引数はアプリを指定する。vimを任意のアプリにできる(フルパス指定でも可)
  • 画像などをBLOB型データにしてGIMPアプリなどへ渡してやることも可
UPDATE posts SET body=edit(body, '/usr/local/bin/vim') WHERE id=1;

vimで画面崩壊

vimで画面崩壊

 edit(列, 'vim')すると以下のようなエラーが出る。

Vim: 警告: 端末からの入力ではありません

 その後、以下のような症状が現れる。

  • 入力した文字が表示されない
  • Enterキー入力しても改行されない
  • 表示に無駄なスペースがやたら入る

 たとえばselect * from posts;したら以下のように表示された。

                                                 System command returns 256
                                                                           id|title|body
                                                                                        1|タイトル|# 見出し

                                                                                                           * 項目A
                                                                                                                  * 項目B

 以下コマンドで直せる。

stty sane

 だが、SQLite3対話モードである。そこで以下コマンドを使った。

.shell stty sane

 すると以下のように怒られた。

stty: 標準入力: デバイスに対する不適切なioctlです

 仕方ないので親元のrun.shスクリプトファイル内で以下を実行した。

stty sane

 ターミナルは謎の罠で満ちている。

 GUIエディタで編集すべきなのか?

所感

 なぜかedit関数などの情報が全然見つからなかった。おかしいでしょ。めちゃくちゃ便利でしょこれ! もっとアピールして!

 もちろん公式には書いてあるのだが、カテゴリおかしくない? なぜCLIとしてreadfile関数などのことが書かれてるのか。

 以下のようにSQL関数一覧に「File I/O関数」ページを作ってまとめてくれたら発見率が高まりSQLite3流行るよ! たぶん。

対象環境

$ uname -a
Linux raspberrypi 4.19.42-v7+ #1218 SMP Tue May 14 00:48:17 BST 2019 armv7l GNU/Linux

前回まで