himorogiの日記

主にプログラミングに関することなど。少々ハード(電子工作)についても。

M1 Mac mini と Deno

Homebrew から Powershell を search すると Powershell-preview しか見えないので、まだ M1 Mac mini には install してない。
このため Powershell から Ruby と Deno に移行しようと思った(のが前回の記事)。

Ruby はこれまで書籍を色々買い込んでたので、それら書籍を読んでたが…老眼で非常に読みづらい。
左右で視力が違うので、眼鏡かけてもちょっと辛い。

簡単な script なら以前から何度か書いてたけど、Ruby 特有のスタイルに馴染むには他の言語の記憶が邪魔しそうで、書籍で確認する頻度が結構多い。
PowershellPerl に似てたのでその点は楽だったのだが…

というわけで、Javascript なら即書けるので、M1 Mac miniCLI 環境では Deno に専念することにした。

M1 Mac mini と Ruby

2014年モデルの MacBookAir に EIZO のモニタを繋いで使ってたのだけど、sleep から復帰するときに画面が乱れるようになった。
その乱れ方を見てると、どうも video 出力周りの劣化が来てる感じなので、お釈迦になる前に Mac mini 購入(もう1ヶ月以上前)。

今まで shell(での)script は Powershell(pwsh)メインに使ってたけど、ちょっと思うところあって Ruby と Deno に移行しようと模索中。
というわけで、来年の記事は Powershell より Ruby とDeno がメインになると思う。

【macOS】jq を使ってみようかと思ったのだが…

jq

www.amazon.co.jp
という本を買った。

jq は予め macOS に入ってたので、Powershell から利用してみようと思っていたのだけど…

これよく考えたら、Powershelljson を PSObject に Convert して、Format-List か Format-Table に渡せば良いだけ…
macOSPowershell 入れて、普段から shell の代わりに使ってなければそれなりに重宝したんだろうけど…

【macOS】PowerShell から WebAPI を呼ぶ

Web Access

PowerShellmacOS にやってきて、.Net 周りの機能はいろいろ入ってなかったので、てっきり WebClient (というか DownloadFile/DownloadString)は使えないと思っていたのだけど、確認したら既に使えるようになってたし、Invoke-RestMethod や Invoke-WebRequest も使えた。

Yahoo! Open Local Platform

以前 GoogleMap の StreetView をダウンロードする script を公開したけど、今は無償利用でも GoogleMap では決済情報の登録が必須になったようなので、今回は Yahoo! の地図・地域情報を利用した。

YOLP(地図):YOLP(地図) - Yahoo!デベロッパーネットワークdeveloper.yahoo.co.jp

事前準備

Yahoo! の WebAPI は決済情報の登録は不要だけど、WebAPI の呼びしに Client ID が必要になるので予め YahooID を作成し、それに紐付いたアプリケーション毎の Client ID を取得する必要がある。

ご利用ガイド - Yahoo!デベロッパーネットワークdeveloper.yahoo.co.jp

早速やってみる

Yahoo!ID を作成し、Client ID を取得したら、実際にやってみよう。
今回は、気象情報API で特定の場所の降水強度を実測値・予測値として受け取る。

YOLP(地図):気象情報API - Yahoo!デベロッパーネットワークdeveloper.yahoo.co.jp

気象情報API では、場所の指定に経度・緯度を渡す必要がある。
そこで、住所文字列からジオコーダAPI で経度・緯度を取得しておく。

YOLP(地図):Yahoo!ジオコーダAPI - Yahoo!デベロッパーネットワークdeveloper.yahoo.co.jp

Yahoo!ジオコーダAPI を呼ぶ

Client ID は 変数 $CID に格納しておく。
PowerShell から WebAPI を呼び出す方法はいくつかあるけど、ここでは WebClient の DownloadString を使う。
Yahoo! WebAPI の戻り値のデータ・フォーマットは XML が既定値だけど JSONP も選択できる。
PowerShell では XML を簡単に Custom Object へ展開できるので、ここはデフォルトで。

リクエストURL+パラメータ文字列
https://map.yahooapis.jp/geocode/V1/geoCoder?appid=<Client ID>&query=<住所文字列>

手順は以下の通り。

PS /Users/hoge/devPwsh> $CID="<取得した Clinent ID>"
PS /Users/hoge/devPwsh> $yolp = "https://map.yahooapis.jp"        
PS /Users/hoge/devPwsh> $wc = New-Object System.Net.WebClient
PS /Users/hoge/devPwsh> $x = [xml]$($wc.DownloadString( "$yolp/geocode/V1/geoCoder?appid=$CID&query=" + "東京都港区虎ノ門1丁目23"))

というわけで、展開してみる。

PS /Users/hoge/devPwsh> $x

xml                            YDF #comment
---                            --- --------
version="1.0" encoding="utf-8" YDF  xxxcache nohit 0.084, 0.001, 0.001 

PS /Users/hoge/devPwsh> $x.YDF        

xmlns                 : http://olp.yahooapis.jp/ydf/1.0
totalResultsReturned  : 5
totalResultsAvailable : 5
firstResultPosition   : 1
ResultInfo            : ResultInfo
Feature               : {東京都港区虎ノ門1丁目23, 東京都港区虎ノ門1丁目23-3, 東京都港区虎ノ門1丁目23-1, 東京都港区虎ノ門1丁目23-4…}

PS /Users/hoge/devPwsh>

Yahoo!ジオコーダAPI は、該当する住所がデータベースになかったり、また複数の住所がヒット(ここでは枝番の存在)したときに、それらを含めて最大10件の住所情報を返す。(REST request のパラメータ、results(=表示件数)のデフォルトが10件なので。これは最大100件まで指定可能)
今回、最初にヒットした住所がそまま使えるので…

PS /Users/hoge/devPwsh> $x.YDF.Feature[0]

Id          : 13103.18.1.23
Gid         : 
Name        : 東京都港区虎ノ門1丁目23
Geometry    : Geometry
Category    : 
Description : 
Style       : 
Property    : Property

PS /Users/hoge/devPwsh> $x.YDF.feature[0].Geometry                 

Type  Coordinates              BoundingBox
----  -----------              -----------
point 139.75022366,35.66905771 139.74074600,35.66094700 139.75178800,35.67094600

PS /Users/hoge/devPwsh> $x.YDF.feature[0].Geometry.Coordinates
139.75022366,35.66905771
PS /Users/hoge/devPwsh> 

これで、東京都港区虎ノ門1丁目23 の経度・緯度が取得できた。

Yahoo!気象情報API を呼ぶ

PowerShell 3.0 から、Invoke-RestMethod と Invoke-WebRequet が使えるようになったので、今度は Invoke-RestMethod を使ってみる。

リクエストURL+パラメータ文字列
https://map.yahooapis.jpweather/V1/place?appid=<Client ID>&coordinates=<経度>,<緯度>

手順は以下の通り。
Yahoo! の WebAPI を利用するなら Invoke-RestMethod が一番手間がかからない。

PS /Users/hoge/devPwsh> $yolp = "https://map.yahooapis.jp" 
PS /Users/hoge/devPwsh> $y = Invoke-RestMethod -Uri $("$yolp/weather/V1/place?appid=$CID&coordinates=" + "139.75001544,35.66663019")
PS /Users/hoge/devPwsh> $y

xml                            YDF
---                            ---
version="1.0" encoding="UTF-8" YDF

PS /Users/hoge/devPwsh> $y.YDF

xmlns                 : http://olp.yahooapis.jp/ydf/1.0
firstResultPosition   : 1
totalResultsAvailable : 1
totalResultsReturned  : 1
ResultInfo            : ResultInfo
Feature               : Feature


PS /Users/hoge/devPwsh> $y.YDF.Feature

Id                              Name                                                                  Geometry Property
--                              ----                                                                  -------- --------
202102071115_139.75002_35.66663 地点(139.75002,35.66663)の2021年02月07日 11時15分から60分間の天気情報 Geometry Property

PS /Users/hoge/devPwsh>

正常に取得できてる模様なので、早速展開してみる。

PS /Users/hoge/devPwsh> $y.YDF.feature.Property

WeatherAreaCode WeatherList
--------------- -----------
4410            WeatherList

PS /Users/hoge/devPwsh> $y.YDF.feature.Property.WeatherList

Weather
-------
{Weather, Weather, Weather, Weather…}

PS /Users/hoge/devPwsh> $y.YDF.feature.Property.WeatherList.Weather

Type        Date         Rainfall
----        ----         --------
observation 202102071115 0.00
forecast    202102071125 0.00
forecast    202102071135 0.00
forecast    202102071145 0.00
forecast    202102071155 0.00
forecast    202102071205 0.00
forecast    202102071215 0.00

PS /Users/hoge/devPwsh>

降水強度(気象レーダーからの換算値)が獲得できた。

【macOS】PowerShell から SQLite を使うための備忘録【.import】

CSV の import なら SQLite の DotCommand でもできるけど…

昨日書いたのは、要するに CSV のデータを PowerShell で読み込んで INSERT Query 生成して SQLite に読み込ませる手順。
CSV import なら SQLite 自身、.import コマンドで対応できる…が…

とにかく一度やってみよう。

まずCSV を準備(昨日の使いまわし)

Proverb.csv

"ID","name","phrase"
"1","厩戸皇子","以和爲貴"
"2","釈迦","天上天下唯我独尊"
"3","孔子","有朋自遠方来不亦楽乎"
"4","杜甫","国破山河在"

CSV にもいろいろなフォーマットがあるが、普通はこういう形。
ところが、SQLite では separator の default は '|' なので、昨日 INSERT した結果を SELECT したら…

PS /Users/hoge/handleProverb> ./selectProverb.ps1
1|厩戸皇子|以和爲貴
2|釈迦|天上天下唯我独尊
3|孔子|有朋自遠方来不亦楽乎
4|杜甫|国破山河在
PS /Users/hoge/handleProverb>

こうなる。

.import の実例

.import でそのまま Proverb.csv を読むと、カラムの判別ができないので、.separetor , で変更しないといけない。
*1
面倒なんで、CREATE TABLE から .import , SELECT を一括して処理したのが以下の通り。

importProverb.ps1

@"
CREATE TABLE Proverb ( id, name, phrase );
.separator ,
.import ./Proverb.csv Proverb
SELECT * FROM Proverb;
"@ | sqlite3 ./myFirst.db $_

実行結果は…

PS /Users/hoge/handleProverb> ./importProverb.ps1
ID,name,phrase
1,厩戸皇子,以和爲貴
2,釈迦,天上天下唯我独尊
3,孔子,有朋自遠方来不亦楽乎
4,杜甫,国破山河在
PS /Users/hoge/handleProverb>

はい、読み込めてます…が、最初のレコード、header が入ってる。
つまり、.import で読み込む CSV には header 入れちゃ拙い。 .import のパラメータには header 無視するとかいう指定はない(はず)。
まぁ、予め CSV の一行削除するとか、DELETE 文で header 削除するとかやりようはあるけど、要するに手間が一つ余計にかかる(とはいっても、上記の例なら .import の直後に DELET 文一行追加するだけなので大した手間ではないけど、これを忘れてうっかり header 残したままにすることが、実は一番の問題だと思う)。

そういうわけで私はあんまり .import 使わないのだけど、大量のレコードを読み込む必要があって PowerShell の遅さに我慢できないときは、予め CSV の header 削除するか、DELETE文追加するくらいの手間と header 消し忘れるリスクは許容できる…かもしれない。

【追記】

せっかくなので、CSV の header 行削除板を…

importProverbHeaderless.ps1

get-content ./Proverb.csv | Select-Object -skip 1 | set-content ./ProverbHeaderless.csv
@"
CREATE TABLE Proverb ( id, name, phrase );
.separator ,
.import ./ProverbHeaderless.csv Proverb
SELECT * FROM Proverb;
"@ | sqlite3 ./myFirst.db $_

実行結果も…

PS /Users/hoge/handleProverb> ./importProverbHeaderless.ps1 
1,厩戸皇子,以和爲貴
2,釈迦,天上天下唯我独尊                                                                                                    
3,孔子,有朋自遠方来不亦楽乎
4,杜甫,国破山河在
PS /Users/hoge/handleProverb>

*1:【2021/01/13 追記】 .separator による default 値の変更は session 中のみ有効なので、毎回指定する必要がある(はず)。

【macOS】PowerShell から SQLite を使うための備忘録

前振り

現役時代 Windows 環境では PowerShell 活用し、業務では結構大量のデータを扱ってたために MS Access より SQLite を重宝してた。
定年リタイアで mac 専科に復帰したため、script は専ら Javascript でやろうと思ってたが、JXA は過疎ってるし node.js は逆に Version 管理面倒くさい…
とか思ってたら PowerShell core の登場で mac でも PowerShell が使えるように。

…が、リタイアしちゃったので、あんまり PowerShell 使う必要性に迫られない。
一応、pwsh を VSCode の terminal に常時立ち上げて shell として使ってるが、script 書くことは稀。

流石にこれではいかんと SQLite のハンドリングする PowerShell の script 書いてたら、どちらも暫く使ってないので結構忘れてた。
しかも今や老眼で、昔ならリファレンスやハンドブックを気軽に検索できたことが目が滑って全然頭に入らない。

というわけで、もっと老化(老眼や記憶力の低下)が進んだときに備え :-p) 基本の基本、あえて書くほどでもない極々当たり前の tips を、紙のメモだと見辛いのでここに記す。

sample データを準備する(csv

writeProverb2CSV.ps1

@"
1,厩戸皇子,以和爲貴
2,釈迦,天上天下唯我独尊
3,孔子,有朋自遠方来不亦楽乎
4,杜甫,国破山河在
"@ | ConvertFrom-CSV -header "ID","name","phrase" | Export-CSV Proverb.csv -NTI

いきなり script 出たけど、CSV ファイル構築するのに、Excel から引っ張ると妙な自動変換されることがあるし、text editor で編集するのは、" や ’ で item 毎に毎回文字列括るのが面倒。だからここでは here document で列挙し、それを一旦 ConvertForm-CSV に渡し、Export-CSV で書き出した。

Export-CSV の -NTI パラメータは PowerShell ver6 以降では要らないみたい…

以下は here document 使わない場合。

ConvertFrom-CSV(
    "1,厩戸皇子,以和爲貴",
    "2,釈迦,天上天下唯我独尊",
    "3,孔子,有朋自遠方来不亦楽乎",
    "4,杜甫,国破山河在"
) -header "ID","name","phrase" | Export-CSV Proverb.csv -NTI

その結果の Proverb.csv

"ID","name","phrase"
"1","厩戸皇子","以和爲貴"
"2","釈迦","天上天下唯我独尊"
"3","孔子","有朋自遠方来不亦楽乎"
"4","杜甫","国破山河在"

まぁ、実際にデータを準備するときは Google SpreadSheet などから直接 CSV 引っ張ってくると思う…

SQLite データベースファイルを作る

macOS だと、Windows 7 まで(Window 10 はあんまり知らない)のときみたいに encoding など default 設定弄る必要ないので、いきなり始められるのが嬉しい。
createProverb.ps1

sqlite3 ./myFirst.db "CREATE TABLE Proverb ( id, name, phrase );"
CSV から SQLite データベースファイルを初期化する

こういう query を渡したいけど面倒なので…

INSERT INTO Proverb ( id, name, phrase ) values( 1, '厩戸皇子', '以和爲貴' );
INSERT INTO Proverb ( id, name, phrase ) values( 2, '釈迦', '天上天下唯我独尊' );
INSERT INTO Proverb ( id, name, phrase ) values( 3, '孔子', '有朋自遠方来不亦楽乎' );
INSERT INTO Proverb ( id, name, phrase ) values( 4, '杜甫', '国破山河在' );

CSV から読み出して script で query 文字列生成して SQLite に渡す。

initProverbFromCSV.ps1

Import-CSV ./Proverb.csv | ForEach-Object{
    "INSERT INTO Proverb ( id, name, phrase ) values( $($_.ID), '$($_.name)', '$($_.phrase)' );"
} | sqlite3 ./myFirst.db $_

$($_.ID) と $() で括ってるのは文字列中に埋め込んでるから、正常に parse できるようにするため。

テーブルに正しく反映されたか確認

selectProverb.ps1

sqlite3 ./myFirst.db "SELECT * FROM Proverb;"

結果

PS /Users/hoge/handleProverb> ./selectProverb.ps1
1|厩戸皇子|以和爲貴
2|釈迦|天上天下唯我独尊
3|孔子|有朋自遠方来不亦楽乎
4|杜甫|国破山河在
PS /Users/hoge/handleProverb>
おまけ

敢えて書くほどのことでもないが…

deletProverb.ps1

sqlite3 ./myFirst.db "DELETE FROM Proverb;"

Twitter のアカウントロック喰らったっぽい(続

twitter については、正直、最近ちょっと時間費やしすぎてると思ってた。
定年で実務からリタイアして2年過ぎ、毎日 tweet しているわりには新しいネタも出てこないから、このままフェードアウトしようかと思う。
それにわけのわからないアカウントロックが横行するサービスでは、情報発信以前にライフログとして使えないしなぁ。

そういうわけで、こっちでまた program なネタを書いてゆこう。