Jupyterのセルmagicである%%bashや%%cmdと同じように新しい%%scriptのショートカットの登録

# 概要

Jupyterのセルmagicである`%%bash`や`%%cmd`は`%%script bash`,`%%script cmd`のショートカットです。`%%bash?`を実行すると確認できます。 あらかじめ登録されている以外のショートカットの簡単な登録方法を紹介します。

# 環境

- Windows 10
- Python3.7
- Jupyter Lab


# 現状の確認

現在使えるセルmagic一覧を確認します

```
%lsmagic
```

以下はセルmagicのみ抽出したものです

```
js: "DisplayMagics"
javascript: "DisplayMagics"
latex: "DisplayMagics"
svg: "DisplayMagics"
html: "DisplayMagics"
markdown: "DisplayMagics"
prun: "ExecutionMagics"
debug: "ExecutionMagics"
timeit: "ExecutionMagics"
time: "ExecutionMagics"
capture: "ExecutionMagics"
sx: "OSMagics"
system: "OSMagics"
!: "OSMagics"
writefile: "OSMagics"
script: "ScriptMagics"
sh: "Other"
bash: "Other"
perl: "Other"
ruby: "Other"
python: "Other"
python2: "Other"
python3: "Other"
pypy: "Other"
cmd: "Other"
SVG: "Other"
HTML: "Other"
file: "Other"
```

# %%scriptのHELP


`%%script?`で使い方が、`%%script??`でソースが表示されます

```
%%script?
```
```
Docstring:
::

  %shebang [--no-raise-error] [--proc PROC] [--bg] [--err ERR] [--out OUT]

Run a cell via a shell command

The `%%script` line is like the #! line of script,
specifying a program (bash, perl, ruby, etc.) with which to run.

The rest of the cell is run by that program.

Examples
--------
::

    In [1]: %%script bash
       ...: for i in 1 2 3; do
       ...:   echo $i
       ...: done
    1
    2
    3

optional arguments:
  --no-raise-error  Whether you should raise an error message in addition to a
                    stream on stderr if you get a nonzero exit code.
  --proc PROC       The variable in which to store Popen instance. This is
                    used only when --bg option is given.
  --bg              Whether to run the script in the background. If given, the
                    only way to see the output of the command is with
                    --out/err.
  --err ERR         The variable in which to store stderr from the script. If
                    the script is backgrounded, this will be the stderr
                    *pipe*, instead of the stderr text itself and will not be
                    autoclosed.
  --out OUT         The variable in which to store stdout from the script. If
                    the script is backgrounded, this will be the stdout
                    *pipe*, instead of the stderr text itself and will not be
                    auto closed.
File:      c:\ ..... \lib\site-packages\ipython\core\magics\script.py
```

```
%%script??
```
出力結果は長いので自分で確かめてください。

# 新しいショートカットの登録

今回登録するのは`julia`言語にしてみました。 

`%%script?`を実行したとき最終行の`File:`に記載されている`script.py`を変更します。下記の`'julia',   # 追加`が変更箇所です。 私の環境では**92行目**です。

```python:script.py
    @default('script_magics')
    def _script_magics_default(self):
        """default to a common list of programs"""
        
        defaults = [
            'sh',
            'bash',
            'perl',
            'ruby',
            'python',
            'python2',
            'python3',
            'pypy',
            'julia',   # 追加
        ]
```

Jupyterのメニューから`Restart Kernel`をクリックして、変更を反映させます。では、確認します。

```
%%julia?
```
```
Docstring:
%%julia script magic

Run cells with julia in a subprocess.

This is a shortcut for `%%script julia`
File:      c:\ ..... \lib\site-packages\ipython\core\magics\script.py
```

これでショートカットが出来ました。次に実行してみます。

```
%%julia
versioninfo()
println()
println("hello world!")
```
```
Julia Version 1.1.1
Commit 55e36cc308 (2019-05-16 04:10 UTC)
Platform Info:
  OS: Windows (x86_64-w64-mingw32)
  CPU: Intel(R) Core(TM) i7-8550U CPU @ 1.80GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)

hello world!
```

Windowsでいつも気になるのが日本語の扱いです。簡単なテストをしてみます。

```
%%cmd
time /?
echo abcdefg
echo "あいうえお"
```

```
Microsoft Windows [Version 10.0.17134.829]
(c) 2018 Microsoft Corporation. All rights reserved.

C:\ .... \notebooks>time /?
システム時刻を表示または設定します。

TIME [/T | 時刻]

パラメーターの指定がなければ、現在の設定が表示され、新しい時刻を入力できる
プロンプトになります。変更しない場合は、Enter キーを押してください。

コマンド拡張機能を有効にすると、TIME コマンドは、/T スイッチを
サポートするようになります。このスイッチを指定すると、現在の時刻
だけが表示され、新しい時刻を入力するためのプロンプトは表示されません。

C:\ .... \notebooks>echo abcdefg
abcdefg

C:\ .... \notebooks>echo "縺ゅ＞縺・∴縺・
"縺ゅ＞縺・∴縺・
```

同様にjuliaでもテストします。

```
%%julia
println("あいうえお")
```
```
縺ゅ＞縺�縺医♀
```

`time /?`の出力は**SJIS**で`echo "あいうえお"`や`println("あいうえお")`はcmdやjuliaに渡されときは**utf-8**で出力も**utf-8**なので文字化けしていると考えられます。LinuxやMacの場合は入出力が両方とも**utf-8**で問題ないと思います。
`julia`は文字コードが**utf-8**なので出力が**utf-8**で問題ないように考えたほうが良さそうです。そこで、`script.py`に以下の変更をします。 **222行目**付近です。

```python
            except Exception as e:
                print("Error while terminating subprocess (pid=%i): %s" \
                    % (p.pid, e))
            return
        if (cmd[0] in ['julia'] and os.name == 'nt'):   # 変更
           out = py3compat.decode(out,encoding='utf8')  # 変更
        else:                                           # 変更
           out = py3compat.decode(out)                  # 変更
        err = py3compat.decode(err)
```

`Restart Kernel`で変更を反映させて再実行

```
%%julia
println("あいうえお")
```
```
あいうえお
```

うまく行きました。

# まとめ

ショートカットの登録は簡単に出来ました。ただし、`script.py`の更新権がないとできません。`config file`やその他の設定で出来るのかどうかは不明です。