無機野

ここはお前の日記帳

xonshがいい感じ

環境:ubuntu 16.04

 

pythonで書かれた代替シェルのxonshがいい感じっぽい
シェルスクリプトpythonの統合する目論見としては他にpysh
https://github.com/yunabe/pysh
があって、でもこちらは最終更新が6年前とかなのでなんか嫌

 

pip install xonsh
でインストール


適当なエディタ開いてシェルスクリプトを書く際、しれっとpythonコードを忍ばせても普通に動いてかなりエモい

 

チュートリアル
https://xon.sh/docs-ahundt-sphinx-readable-theme-pypi/tutorial.html
を参照

 

例えば、
$ ls -a
. .. test.sh url.txt
$ ls,a = 100,1
$ ls -a
99
みたいな感じでやばい

 

スクリプトは行ごとにpythonモードとsubprocessモードで解釈されるっぽい
xonshが変数を見つけられなかった場合subprocessモードで(要はシェルコマンドとして解釈)され、そうでない場合pythonモードで解釈されるらしい
各モードを強制したい場合は以下みたいな感じ

 

・' '
xonshで特別な意味のある記号などを無視する
>>> echo '${'
${
bashのみたいなエスケープシーケンスは無いらしい

 

・$()
シェルコマンドの標準出力をpythonのstr型で返す
>>> $(ls -l)
'total 0 -rw-rw-r-- 1 snail snail 0 Mar 8 15:46 xonsh '

 

・!()
$()は標準出力のみ返したけどさらに多くの情報を返す
CommandPipelineというクラスのインスタンスとして生成されるっぽい たぶん見ればわかる
>>> !(ls nonexistent_directory)
CommandPipeline(stdin=<_io.BytesIO object at 0x7f1948182bf8>, stdout=<_io.BytesIO object at 0x7f1948182af0>, stderr=<_io.BytesIO object at 0x7f19483a6200>, pid=26968, returncode=2, args=['ls', 'nonexistent_directory'], alias=['ls', '--color=auto', '-v'], stdin_redirect=['<stdin>', 'r'], stdout_redirect=[9, 'wb'], stderr_redirect=[11, 'w'], timestamps=[1485235484.5016758, None], executed_cmd=['ls', '--color=auto', '-v', 'nonexistent_directory'], input=None, output=, errors=None)

 

・$と!
で囲むものはuncaptured subprocessesと呼ばれる
xonshをスルーして画面に直接表示される
その返り値は常にNone
他は()の場合とほぼ同じ
>>> x = $[ls -l]
total 0
-rw-rw-r-- 1 snail snail 0 Mar 8 15:46 xonsh
>>> x is None
True

 

・@()
subprocessモードで動き、括弧の中身をpythonコードとして解釈する
結果がなんだろうとstr型に変換されてsubprocess command listに追加されていく

 

・@$()
@([i.strip() for i in $(cmd).split()])
と同じ

 


pythonのfor文の中にそのままシェル文書くみたいなことできてかなり良い
例えば

#! /hoge/fuga/xonsh
urllist = open("url.txt").read().split()
for i in range(len(urllist)):
    youtube-dl --get-title --skip-download @(urllist[i])

みたいに書けてやばいエモい

 

いままで
import subprocess
して
cmd = ["aaa", "uuu"]
subprocess.run(cmd,stdout=untara,hogehoge)
みたいに書いてたのが間抜けに思える

 

注意点としてpythonモードで設定した変数をsubprocessモードで参照するときつい${arg}って書きそうになるけど、pythonモードで宣言しただけではsubprocessモードで参照できない(?)っぽいので@()で囲むことで明示的にアレする必要あり これで30分くらいハマった(かわいい)

 

あと先述したようにsubprocess modeでエスケープシーケンス使えないっぽいので、たとえばシェル文の中で大括弧使いたいときなんか構文エラー出るのに¥[hoge¥]みたいな書き方できない、しかもなぜかシングルクォーテーションでも通らない(why?)

そういうときはpythonモード経由して、つまり@("[hoge]")みたいに書くとなんか通る  多分もう少し賢いやり方あるはず

 


エモい
おわり