xonshでscreenfetchするとpythonx.xって出て悲しい

``` shell
$ screenfetch
           /:-------------:\          user@host
        :-------------------::        OS: Fedora 30 Thirty
      :-----------/shhOHbmp---:\      Kernel: x86_64 Linux 5.3.16-200.fc30.x86_64
    /-----------omMMMNNNMMD  ---:     Uptime: 13h 27m
   :-----------sMMMMNMNMP.    ---:    Packages: 2531
  :-----------:MMMdP-------    ---\   Shell: python3.8
 ,------------:MMMd--------    ---:   Resolution: 1920x1080
 :------------:MMMd-------    .---:   DE: GNOME 
 :----    oNMMMMMMMMMNho     .----:   WM: GNOME Shell
 :--     .+shhhMMMmhhy++   .------/   WM Theme: Adwaita
 :-    -------:MMMd--------------:    GTK Theme: Adwaita [GTK2/3]
 :-   --------/MMMd-------------;     Icon Theme: Adwaita
 :-    ------/hMMMy------------:      Font: Cantarell 11
 :-- :dMNdhhdNMMNo------------;       CPU: Intel Core i7-8550U @ 8x 4GHz
 :---:sdNMMMMNds:------------:        GPU: Mesa DRI Intel(R) UHD Graphics 620 (Kabylake GT2) 
 :------:://:-------------::          RAM: 6817MiB / 15779MiB
 :---------------------://            
```

Shell:を見ての通りちょっと悲しい。そもそもscreenfetchってどうシェルをとってるんだ？と思ったので読む話。あとできればXonshって表示してほしい。

# screenfetchを読もう

[screenfetch:GitHub](https://github.com/KittyKatt/screenFetch/)

screenfetchって1つのシェルスクリプトなんですね・・・こわ
どうやらscreenfetch-devってのが本体っぽい。

で、シェル関係が知りたいのでshellでCtrl+F。

すると黄色具合から1843行目の`detectshell()`があやしい。

とりあえず読んでみよう

ひとまず前半を示す。

``` shell
detectshell () {
	if [[ ! "${shell_type}" ]]; then
		if [[ "${distro}" == "Cygwin" || "${distro}" == "Msys" || "${distro}" == "Haiku" || "${distro}" == "Alpine Linux" ||
			"${distro}" == "Mac OS X" || "${distro}" == "TinyCore" || "${distro}" == "Raspbian" || "${OSTYPE}" == "gnu" ]]; then
			shell_type=$(echo "$SHELL" | awk -F'/' '{print $NF}')
		elif readlink -f "$SHELL" 2>&1 | grep -q -i 'busybox'; then
			shell_type="BusyBox"
		else
			if [[ "${OSTYPE}" =~ "linux" ]]; then
				shell_type=$(tr '\0' '\n' </proc/$PPID/cmdline | head -1)
			elif [[ "${distro}" =~ "BSD" ]]; then
				shell_type=$(ps -p $PPID -o command | tail -1)
			else
				shell_type=$(ps -p "$(ps -p $PPID | awk '$1 !~ /PID/ {print $1}')" | awk 'FNR>1 {print $1}')
			fi
			shell_type=${shell_type/-}
			shell_type=${shell_type//*\/}
		fi
	fi

        .....

	myShell=${shell_type}
	verboseOut "Finding current shell...found as '$myShell'"
}
```

実際`-v`オプションをつけて見てみると`verboseOut "Finding current shell...found as '$myShell'"`の行が動いてることがわかる。

まずは最初のifの中を見よう。

`$shell_type`ってのがシェル＿タイプの変数っぽい(小泉進次郎風に)。
まずはOSの種類を見てからOSにあわせてシェルを取得してるっぽい。
OSの種類はlinuxなので`if [[ "${OSTYPE}" =~ "linux" ]]`のブロックを見よう。ちなみに`=~`は正規表現比較らしい。いま知った。

まあ見たらわかるように、`tr '\0' '\n' </proc/$PPID/cmdline | head -1`がシェル＿タイプってこと。後ろでちょっと加工してるけどまあそれはまた後に。


`/proc/$PPID/cmdline`は、大体名前から察するように$PPIDのプロセスのコマンド。`$PPID`がなんのpidなのかわからないがおそらくシェルのだろう。どっか他のコードでとってるんじゃないですかね。まあ見てみよう。

``` shell
$  ps
  PID TTY          TIME CMD
20316 pts/5    00:00:01 xonsh
21745 pts/5    00:00:00 ps

$  cat /proc/20316/cmdline                                                          
/home/tia/.pyenv/versions/3.8.1/bin/python3.8-u/home/tia/.pyenv/versions/3.8.1/bin/xonsh--login
```

はい。まあ予想通りですね。と思ったけどなんか変だ。python3.8-u???なにこれと思ったけど右の方を見て察した。スペースが抜けてる。
なんでだろ。まあいいか。

xonshは直接xonshのバイナリを起動してるんじゃなくてpythonを起動してる。いやそれはそう。当たり前やん。

ですがまあ、なんとなく原因がわかりましたね。screenfetchはシェルを起動してるコマンドを取得してシェルの名前を取り出しているので、直接シェルじゃなくてpythonを起動しているxonshはxonshじゃなくてpythonと見られてしまう。

ついでにtrコマンドとheadコマンドを見てみよう。僕がしらないので。

...ｇｇりタイム...

`tr`は文字の入れ替え。`str.replace()`。`echo hoge | tr 'hoge' 'fuga'`で`'hoge'.replace('hoge', 'fuga')`って意味。pythonで言うと

`head`は指定行の取り出し。`str.splitlines(False)[n]`。`echo "hoge\nfuga" | head -1`で`'hoge\nfuga'.splitlines(False)[0]`って意味。


で、cmdlineの中身を`tr '\0' '\n'`してる。うーん、あ、さっきスペースが抜けてるって思ったところ、スペースじゃなくて`\0`が入ってるのかも知れない。まあ実際打ってみればわかるか。

``` shell
$  tr '\0' '\n'  < /proc/20316/cmdline
/home/tia/.pyenv/versions/3.8.1/bin/python3.8
-u
/home/tia/.pyenv/versions/3.8.1/bin/xonsh
--login
```
 
おっけい。多分それっぽい。ちゃんと改行されてる。

そして、これに`head -1`してるので、1行目を取り出している。つまり、`/home/tia/.pyenv/versions/3.8.1/bin/python3.8`。
完全にこれだ。


で、最後に

``` shell
shell_type=${shell_type/-}
shell_type=${shell_type//*\/}
```

。多分/の一番右を取り出してるんだろう。

これでシェル＿タイプがわかりましたね。



さて、後半。


``` shell

detectshell () {

        ......

	case $shell_type in
		bash)
			shell_version_data=$( detectshell_ver "$shell_type" "^GNU.bash,.version" "4" )
			;;
		BusyBox)
			shell_version_data=$( busybox | head -n1 | cut -d ' ' -f2 )
			;;
		csh)
			shell_version_data=$( detectshell_ver "$shell_type" "$shell_type" "3" )
			;;
		dash)
			shell_version_data=$( detectshell_ver "$shell_type" "$shell_type" "3" )
			;;
		ksh)
			shell_version_data=$( detectshell_ver "$shell_type" "version" "5" )
			;;
		tcsh)
			shell_version_data=$( detectshell_ver "$shell_type" "^tcsh" "2" )
			;;
		zsh)
			shell_version_data=$( detectshell_ver "$shell_type" "^zsh" "2" )
			;;
		fish)
			shell_version_data=$( fish --version | awk '{print $3}' )
			;;
	esac

	if [[ -n $shell_version_data ]];then
		shell_type="$shell_type $shell_version_data"
	fi

	myShell=${shell_type}
	verboseOut "Finding current shell...found as '$myShell'"
}
```


これは・・・・・・完全無視だ。`$shell_type`が`bash, BusyBox, csh, dash, ksh, tcsh, zsh, fish`のどれかならバージョンを読むっぽい。無視無視。


さあて、結論が出ました。

xonshはbashとかのように`bash`と直接呼び出しているわけでなく`python xonsh`とpythonの上に動いているので、直接呼び出されているpytohnがシェルとして検出される。以上。


# 対策

`detectshell()`の一行目を見てみましょう。

``` shell
detectshell () {
    if [[ ! "${shell_type}" ]]; then
...
```

そう、最初に既に`$shell_type`が設定してあるか見てるのだ。つまり対策としては


``` shell
$ $shell_type = $(xonsh -V).strip()
$ screenfetch
```
以上！

```
           /:-------------:\          user@host
        :-------------------::        OS: Fedora 30 Thirty
      :-----------/shhOHbmp---:\      Kernel: x86_64 Linux 5.3.16-200.fc30.x86_64
    /-----------omMMMNNNMMD  ---:     Uptime: 14h 28m
   :-----------sMMMMNMNMP.    ---:    Packages: 2531
  :-----------:MMMdP-------    ---\   Shell: xonsh/0.9.13.dev1
 ,------------:MMMd--------    ---:   Resolution: 1920x1080
 :------------:MMMd-------    .---:   DE: GNOME 
 :----    oNMMMMMMMMMNho     .----:   WM: GNOME Shell
 :--     .+shhhMMMmhhy++   .------/   WM Theme: Adwaita
 :-    -------:MMMd--------------:    GTK Theme: Adwaita [GTK2/3]
 :-   --------/MMMd-------------;     Icon Theme: Adwaita
 :-    ------/hMMMy------------:      Font: Cantarell 11
 :-- :dMNdhhdNMMNo------------;       CPU: Intel Core i7-8550U @ 8x 4GHz
 :---:sdNMMMMNds:------------:        GPU: Mesa DRI Intel(R) UHD Graphics 620 (Kabylake GT2) 
 :------:://:-------------::          RAM: 6954MiB / 15779MiB
 :---------------------://           
                       
```