2019/10/06

q を使って CSV ファイルに SQL を発行する

"q" という、CSV や TSV に SQL をに発行できるコマンドがあります。
便利なのですが、名前がググりづらいことこの上無い感じですね。


環境

  • OS: macOS Mojave 10.14.6
  • Homebrew: 2.1.12-8-gfd9a09e
    • homebrew-core: (git revision 5b99; last commit 2019-10-05)
  • q: 1.7.4


インストール方法

  • $ brew install q
でインストールできます。


実行例

例えば、以下のような "servant.csv" があったとして


以下のように SQL が発行できます。
  • select
    • $ q -d, -H 'select * from servant.csv ;'
      • 1,Altria Pendragon,saver,5
      • 2,Altria Pendragon (alter),saver,4
      • 3,Altria Pendragon,archer,5
      • 4,Altria Pendragon,lancer,5
      • 5,Altria Pendragon (alter),lancer,4
  • count
    • $ q -d, -H 'select count(*) from servant.csv ;'
      • 5
  • limit
    • $ q -d, -H 'select * from servant.csv limit 2;'
      •  1,Altria Pendragon,saver,5
      •  2,Altria Pendragon (alter),saver,4
  • distinct
    • $ q -d, -H 'select distinct(name) from servant.csv ;'
      •  Altria Pendragon
      •  Altria Pendragon (alter)
  • where
    •  $ q -d, -H 'select id,name,class from servant.csv where rarity = 5;'
      •  1,Altria Pendragon,saver
      •  3,Altria Pendragon,archer
      •  4,Altria Pendragon,lancer
  • order 
    • $ q -d, -H 'select * from servant.csv order by rarity;'
      •  2,Altria Pendragon (alter),saver,4
      •  5,Altria Pendragon (alter),lancer,4
      •  1,Altria Pendragon,saver,5
      •  3,Altria Pendragon,archer,5
      •  4,Altria Pendragon,lancer,5
  • distinct + count
    •  $ q -d, -H 'select count(distinct(name)) from servant.csv ;'
      •  2
なお、付けているオプションは
  • -d (--delimiter) 今回は csv なので  ','  が delimiter です。
  • -H (--skip-header) 今回は一行目に header があるので、それは値としてみなしません。
    • と、いうことは header が無い場合も想定していると思われます(やったこと無し)。
です。--help は貴重な情報源。


まとめ

と、いう感じで、"q" を使うと CSV を色々いじったりできて便利です。
ちなみに、 Office で開くと重かったり止まったりするサイズの csv でも捌いてくれます。つよい。


参考

2019/09/21

git clean を使って untracked なファイルを削除する

Mercurial には hg purge というコマンドがあって、 hg で control していないファイルを一括削除できます。
具体的には add してないファイルとか、.c から作った .o とか、間違って作った Rails の migration とか。
それを Git でもできないかなー、と調べたメモ。


環境

  • OS: macOS Mojave 10.14.6
  • Git: 2.23.0


git clean

hg purge のようなコマンドは Git にも default でも存在していて、git clean だそうです。

untracked なファイルを消す際は
  • $ git clean -fd
とかすると add してないファイルが消えます。

あとは、すぐに消すのではなく、消す対象が何かを教えてくれる -n (--dry-run) option が便利です。
  • $ git clean -fdn
で削除対象一覧を出してくれます。ちなみに
  • git clean -f -d -n
と書いても良いみたいです。

他には 
  • -X option: .gitignore で指定されたファイルのみを消す
    • .o とかが消えてくれる。
    • あと untracked なファイルは消えない
    • 新規にファイルを作った上で rebuild したい時に便利だよ、とのこと
  • -x option: .gitignore で指定されたファイルも削除対象 + untracked のファイルも削除対象
    • かなり危険なので事前に dry-run を付けた方が良いです
    • git clean -fdx とかすると clone 直後くらい綺麗な状態になります
とかですかね。
さらに詳細を知りたい場合は man git-clean を読んで頂ければ。


参考

2019/09/16

Terminal.app を使って mac を sleep させる

Terminal から mac を sleep させる方法無いかなー、と思ったのでそのメモ。


経緯

私は普段 MacBookPro + Display + Keyboard で作業をしています。
この状態からそのまま MBP を閉じると clamshell mode になってしまいます。
なので MBP を sleep -> MBP を閉める という流れで全体を sleep させています。
MBP を sleep させるには Shift + Control + 電源ボタン の shortcut を使うことが多いです。

しかし、たまに MBP を sleep させずに閉じてしまう時があります。
外付け keyboard には電源ボタンが無い。ので  sleep させられない。
そのせいで一旦閉じた MBP を再度開いて sleep させて閉じる、とかやっていたのですがちょっと面倒。

ということで、外付け Keyboard だけで clamshell mode の MBP を sleep させる方法た無いかな、と思って調べました。


環境

  • OS: macOS mojave 10.14.6 Version (18G95)


コマンド

  • $ pmset sleepnow
sleep させることができます。思ったより楽だった。


2019/09/01

neovim で plugin を利用せずに sudo を使う

root 権限が必要なファイルを neovim や vim で編集する事があると思います。
その際、 sudoers で許可されているユーザならば
  • :write ! sudo tee % > /dev/null
で sudo を使って root として書き込むことができます。

ですが、 neovim では
  • :write ! sudo tee % > /dev/null
    • sudo: no tty present and no askpass program specified
    • shell returned 1
と言われて sudo が使えません。


解決策

以下のようなコマンドを定義することで対応できます。 このコマンドは vim と neovim の両方で利用できます。

vim で利用する場合は ~/.vimrc に追記します。
neovim で利用する場合は ~/.cofig/nvim/init.vim に追記します。


使い方

  • $ nvim /etc/hosts
    • root 権限が必要なファイルを開いて編集します。保存の際は
  • :SudoWriteCurrentBuffer
    • を実行します。
    • パスワードを入力すれば root で書き込む事ができます。


動作確認をした環境

大元の環境(vim と neovim で動作確認済)
  • OS: macOS Mojave 10.14.6 (18G95)
  • Homebrew: 2.1.11
    • Homebrew/homebrew-core: (git revision 883ee; last commit 2019-09-01)
  • neovim: v0.3.8
  • vim: 8.0.1365
  • sudo: version 1.8.17p1
    • Sudoers policy plugin version 1.8.17p1
    • Sudoers file grammar version 45
    • Sudoers I/O plugin version 1.8.17p1
  • docker: 19.03.1, build 74b1e89

    docker を使っていくつかの distribution でも動作を確認
    • Alpine linux: 3.10.2
      • neovim: v0.3.7
      • vim: 8.1.1365
      • sudo: version 1.8.27
        • Sudoers policy plugin version 1.8.27
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.27
    • CentOS: release 7.6.1810 (Core)
      • vim: 7.4.1099
      • sudo: version 1.8.23
        • Sudoers policy plugin version 1.8.23
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.23
    • Fedora: release 30
      • vim: 8.1.1912
      • sudo: version 1.8.27
        • Sudoers policy plugin version 1.8.27
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.27
    • Ubuntu: 18.04.3
      • vim: 8.0.1453
      • sudo: version 1.8.21p2
        • Sudoers policy plugin version 1.8.21p2
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.21p2
    • Debian: 10.0 (buster-20190812)
      • vim: 8.1.1401
      • sudo: version 1.8.27
        • Sudoers policy plugin version 1.8.27
        • Sudoers file grammar version 46
        • Sudoers I/O plugin version 1.8.27


    何故 neovim では sudo が使えないのか

    ここから先は先程の Vimscript を作るに至った経緯を書きます。
    興味のある方はご覧ください。

    まず sudo の error message
    • sudo: no tty present and no askpass program specified
    を見ると、 tty と askpass が無いと言っています。


    tty と askpass

    実際、vim では
    • : ! tty
      • /dev/ttys004 
    などが得られますが、 neovim では
    • : ! tty
      • not a tty
      • shell returned 1
    と言われてしまいます。

    askpass は使ったことが無いのですが、fedora の container で dnf search すると
    の様に、いくつかの askpass が確認できます。のでちょっと試してみます。
    • x11-ssh-askpass
    • openssh-askpass
    • ksshaskpass
    という感じで全然起動してくれません。
    ですがエラーの内容的に display を開こうとしているのが分かります。
    なので、おそらく GUI で password を聞くような物だと思われます。


    askpass を作る

    askpass について調べていると、どうやら
    • password を stdout に出力するもの
    であることが分かりました

    よって
    • neovim 内で password を取得
    • password を stdout に出力する
    • password の履歴はどこにも残さない
    ようなものを作れば解決できそうです。

    それで完成したのが /tmp/askpass を作るこの Vimscript です。

    本当はファイル名は固定でなく tempfile 的な物で対応するなど、改善点はいくつも存在するかと思います。
    ですが私は Vimscript に明るくないので、"3つの条件を満たして動けばOK" という条件で作成しました。
    他により良い対応方法があればご指摘頂けると幸いです。


    その他の解決策

    調べた結果、 suda.vim というプラグインがあるようです。
    また、他にも sudo.vim など、似たようなプラグインはいくつかあるらしいです。

    これを使わなかった理由としては
    • docker のコンテナ内で作業をする事が多々ある
    • init.vim を配置するスクリプトは既にある
    • plugin を install するスクリプトはまだ無い
    • 全コンテナに plugin を入れるのも面倒だし結構サイズがある
      • $ du -sh ~/.config/nvim/repos
        • 100M    /Users/atton/.config/nvim/repos
    などがあります。

    また、"sudo が使えるならこの際 root になってしまう" という解決策もあるのですが
    • 前述した理由の後半3つ
    • 複数人数のユーザが使う環境だと、 /root 配下に自分専用の設定を置くことになる
    のでこちらも無しで。

    他には、 "sudoers で NOPASSWD を設定する" という解決策もあります。
    が、sudo を no password でガンガン使えば実質 root で作業しているのと変わらず、危険すぎるのでこちらも無し。

    ということでこの Vimscript を書くに至った、という訳なのです。


    おまけ: 環境変数の unlet

    スクリプト内部では askpass の場所を示す SUDO_ASKPASS を設定している部分があります。
    具体的には
    • let $SUDO_ASKPASS  = s:askpass_path
    ですね。

    この環境変数を定義していると、 sudo -A した際に指定したファイルが実行されます。
    一応、 :SudoWriteCurrentBuffer の実行後にはなるべく元の環境に戻すために
    • unlet $SUDO_ASKPASS
    を書いていた時もありました。

    ですが動作確認中、 Vim 8.0.1365 で unlet 時にエラーが出てしまいました。
    また 、-A を指定しなければ sudo の動作は変わらないので 、残っていても無害と判断して unlet しない形になりました。


    おまけ: shebang を指定しないとどうなるのか

    ちなみに askpass の shebang を消すと
    • sudo: unable to run /tmp/askpass: Exec format error
    • sudo: no password was provided
    と言われる為、きちんと書いておく必要があります。


    おまけ: x flag を付けないとどうなるのか

    setfperm(s:askpass_path, "rwxr-xr-x")  をせずに 644 のままだと
    • sudo: unable to run /tmp/askpass: Permission denied
      • sudo: no password was provided
      と言われるので、こちらもきちんと指定しておく必要があります。


      参考

      2019/08/29

      tmux 2.9a の window 分割線を ascii character にする

      2019/05/01 に tmux 2.9a がリリースされていました
      残念ながら 2.9 は見逃がしてしまいました。
      ということで恒例の分割線を EastAsianAmbiguous から ascii の線に変更するバージョンを作成。
      2.8の時とか2.7 の時とかの作業履歴とかもまとめてあります。
      そもそもどういう問題なのかはこの記事で。


      環境

      • OS: macOS mojave 10.14.6 (18G95)
      • tmux: 2.9a-border-ascii ( f976aed943f322a3652f51846b0fe472534ab6d6 )
      • Homebrew: 2.1.11
      • Homebrew/homebrew-core: (git revision 269c; last commit 2019-08-29)
      • Font: Ricty: 3.2.2(no option)


      作業

      今回も割とあっさりできました。cherry-pick して tag 更新して終わり。
      • $ git pull upstream
      • $ git checkout 2.9a
      • $ git cherry-pick border-ascii
      • $ git checkout -b 2.9a-border-ascii
      make できるかの確認は
      • $ sh autogen.sh
      • $ ./configure 
      • $ make
      で。

      ちなみに brew edit tmux して本家のビルド手順を参考にしてます。
      あと、 dependencies から utf8proc が消えて ncurses が追加。

      make すると current directory に tmux command ができるので、動作確認も可能。
      • $ ./tmux -V
        • tmux 2.9a
      • $ ./tmux
        • border-ascii 版の tmux が起動します。
      あとは自分用の tap に反映しておしまい。


      インストール方法

      1からインストールする場合のコマンドは
      • $ brew install --HEAD atton/customs/tmux
      でいけます。
      必要あらば自動で atton/cusoms を tap してくれるようになってました。便利。