xonshをつかってみよう

# xonshとは
Pythonでできたシェル。でもってPythonで書ける。linuxのコマンドとも混在可。
シェルスクリプト？？なにそれおいしいのというPythonエンジニアにおすすめ
## 環境
```
$ cat /etc/lsb-release 
DISTRIB_ID=elementary
DISTRIB_RELEASE=5.0
DISTRIB_CODENAME=juno
DISTRIB_DESCRIPTION="elementary OS 5.0 Juno"
```

# install
pipでもaptでもインストールできます
`$ sudo pip install xonsh` (python2と3が混在している場合pip3かな？)
or
`$ sudo apt install xonsh`

で、注意
aptでインストールすると、古いバージョンがインストールされます。
最新版は今0.8.4ですが、多分0.6.0とかが入ると思います。
アプデでPythonの機能が使えるようになってたりいろいろあるので、最新の安定版を使うのが望ましいかなと思います。
じゃあpipしよう。
でpipしたら`/usr/local/bin/xonsh`にインストールされます。
これでログインシェルを変更しようとすると

```
$ chsh
パスワード: 
tia のログインシェルを変更中
新しい値を入力してください。標準設定値を使うならリターンを押してください
	ログインシェル [/bin/bash]: /usr/local/bin/xonsh
chsh: /usr/local/bin/xonsh はシェルに指定できません
```

とか言って来やがります。
というわけでxonshをシェルと認めさせるためには`/etc/shells`に追記します

```
# /etc/shells: valid login shells
/bin/sh
/bin/bash
/bin/rbash
/bin/dash
# 追記
/usr/local/bin/xonsh
```

これで`$ chsh`でいけるはず


設定ファイルいじるのｺﾜｲって人は、aptしたあとにpipすると、2つ(`/usr/bin/xonsh`, `/usr/local/bin/xonsh`)インストールされちゃいますが、なぜか`usr/bin/xonsh`の方(aptではいるやつ)のxonshのバージョンも最新になってます。これで`chsh -s /usr/bin/xonsh`でいけるはず


# 使ってみよう
```
$ echo hoge
hoge
$ ls
Documents   Music   Public   Templates   Downloads   Pictures   Videos
$ pwd
/home/tia
```

という感じに、いつものコマンドはいつものように使えます。
で、Pythonが書けるとどういうことか。

```python
$ print('hoge')
hoge
$ import os
$ os.name
'posix'
$ for i in range(5):
.   print(i)
.
0
1
2
3
4
```

という感じになります。
いつものシェルとして動作するのをsubprocessモード、pythonとして動作するのをpythonモードとか言います。
で、なにが嬉しいかというとpythonのstrとsubprocessの文字列の相互運用ができること

python str から subproess string

```
$ echo @(2 ** 10)
1024
```

subprocess から python

```
$ print($(ls))
Documents
Music
Public
Templates
Downloads
Pictures
Videos
```

はい。

まあ実際いれて触ってみてもらえば早いと思います。
`$()`でsubproccess string からpython str または subproccess string

```
$ echo $(3 * 4)
12
$ echo $(ls)
Documents
Music
Public
Templates
Downloads
Pictures
Videos
```

`$[]`でsubprocessを実行、結果を表示、返り値はNone

```python
$ a = $[echo a]
a
$ a
$ a is None
True
```

`!()`でsubprocessのclassが返ってくる

```python
$ p = !(pwd)
$ p
CommandPipeline(stdin=<_io.BytesIO object at 0x7f8d126014c0>, stdout=<_io.BytesIO object at 0x7f8d126010a0>, stderr=<_io.BytesIO object at 0x7f8d12601360>, pid=5776, returncode=0, args=['pwd'], alias=None, stdin_redirect=['<stdin>', 'r'], stdout_redirect=[4, 'wb'], stderr_redirect=[12, 'w'], timestamps=[1544454131.2289853, 1544454132.1424832], executed_cmd=['/bin/pwd'], input=, output=/home/tia
, errors=None)
$ p.output
'home/tia\n'
```

`![]`でsubprocessを実行、結果を表示、classが返ってくる(HiddenCommandPipelineってやつ)

```python
$ p = ![pwd]
/home/tia
$ p
$ type(p)
xonsh.proc.HiddenCommandPipeline
$ p.returncode
0
```

`@()`でpythonからsubprocess
リストを指定すると順番に実行してくれる

```
import xonsh
$ echo @(xonsh.__version__)
0.8.3
$ l = [1,2,3,4,5]
$ touch @(l)
$ ls
1   2   3   4   5   (省略)
```

for文とかの中にも全然書ける

```
$ for i in range(1,5):
.   touch @(i)
.
$ ls
1   2   3   4   5   (省略)
```


## コマンドを書く
コマンドもPythonで書ける

```
def _my_echo(args, stdin=None):
    print(' '.join(args))

$ aliases['my_echo'] = _my_echo
```

関数を書いて、エイリアスを貼るとコマンドとして使えるようになる。
関数名とエイリアス名を被せないように注意
引数は、ひだりから　
args: 引数がリストに入ってる
stdin : 
stdout: 
stderr:  名前の通りのファイルオブジェクトが流れてくる 

あとまだあるらしいけど、この辺から先は自分がまだ把握できてないので、ptk(ぷろんぷとつーるきっと)とかって調べると幸せになれると思う。

これで例えば（僕が使ってる）ターミナルからgoogle翻訳に飛べるやつ
デフォルトで英語から日本語
-jオプションで日本語から英語
manコマンドの結果をそのまま流して見るとかもできる

```python
def _trans(args, stdin=None):
    from urllib.parse import quote
    from time import sleep

    options = [(index, value) for index, value in enumerate(args) if value[0] == '-']
    options.reverse()
    for i, v in options:
        del args[i]
    
    if '-j' in [v for _, v in options]:
        url = 'https://translate.google.com/?hl=ja&tl=en&text='
    else:
        url = 'https://translate.google.com/?hl=ja&tl=ja&text='

    if stdin is None:
        if not args:
            print('trans {arg[0]}')
            print('_trans(args)')
            return 1
        for w in args:
            text = quote(w)
            chromium-browser @(url+text)
            sleep(1)
    else:
        while True:
            text = quote(stdin.read(5000))
            if text == '':
                break
            chromium-browser @(url+text)
            sleep(1)
```

# まとめて
基本はいつものPythonとLinuxのコマンドです。
あとは、僕自身まだxonshをxonshらしく使いこなせてはいないので、精進します・・・という感じですが・・・
Python大好き他の言語なんてよほどのこと(モバイル開発とか)がないと使いたくない、みたいな人にはとてもおすすめです。なぜなら僕がそうだから