LoginSignup
11
4

Elixirが無い所でもElixirを実行できるシェルスクリプト

Last updated at Posted at 2023-09-01

Elixirプログラマーは Elixirが好きなあまり、ついついなんでもかんでもElixirでプログラムを記述しがちです。その点における一つ課題は、Elixirプログラミングをしない人のPCに必ずしもElixirの実行環境があるわけではなくElixirプログラムを実行できない場合があるということです。

「どこでもエリクサー」みたいなものを作ってみんなが気軽にElixirスクリプトを実行できるようになれば、Elixirプログラマーとして気兼ねなくElixirを書けて嬉しいですし、Elixirプログラミングをしない人にとってもElixirという素敵な世俗派関数型言語 1 に出会う絶好の機会になるともいえます。

Elixirを使ってサーバーの費用を $2 Million/年 節約できたという話が大きく話題になりました。Elixirの素晴らしさをより多くの方々と共有できればなお嬉しいです。

Elixir実行環境の有無を調べる方法

ターミナルでelixirコマンドを打つのが一番簡単だと思います。

ターミナル:Elixirのインストールされていない場合
root@d79eb598ea41:/# elixir
bash: elixir: command not found

他にもいろんなやり方あります。

command -vコマンドの終了値で判定する方法があります。正常終了の時に0、そうで無い場合に1以上の値が終了値となります。

ターミナル:コマンドの解釈に成功した場合
$ command -v bash
/bin/bash

$ echo $?
0
ターミナル:コマンドの解釈に失敗した場合
$ command -v nanjakore

$ echo $?
1

上述の特性を利用してこんな感じで条件分岐することができそうです。

ターミナル
if command -v elixir &>/dev/null; then
  echo "elixir is installed"
else
  echo "where is elixir?"
fi

command -vコマンドは現在のシェル環境が与えられたコマンドをどのように解釈するかを標準出力に出します。ここではそれは不要なのではブラックホール(/dev/null)に放り込んでいます。

Elixirが無い所でElixirスクリプトを実行する方法

Elixirが無い所でElixirスクリプトを実行する方法としては、Dockerが手っ取り早いような気がします。

@torifukukaiou さんの「Qiita CLI で取得した.md ファイルのファイル名を Elixir で変更する」に登場する技が活用できそうです。

ターミナル:ElixirスクリプトをDockerコンテナ内で実行
docker run \
  --rm \
  --mount type=bind,src="$(pwd)",dst=/app \
  --workdir /app \
  elixir:1.15.4-otp-25-slim \
  elixir -e 'File.write("genki.txt", "元氣があればなんでもできる!\n")'

ポイントは、Elixirのイメージを使うことによりコンテナ内でElixirが実行できるようになることと、バインドマウントすることによりコンテナ内でのファイルの変更がホストマシンに反映されることです。

ターミナル:ホストにファイルが生成されたことを確認
$ cat ./genki.txt
元氣があればなんでもできる!

ファイルにするほどでもない短いElixirコードは-eオプションで気軽に実行できます。

以上の技を組み合わせ、本題に取り組みます。

Elixirが無い所でElixirスクリプトを実行するシェルスクリプトを書く

まず、テスト用ディレクトリを作ってその中に入ります。

ターミナル
mkdir -p hoge && cd hoge

テスト用の楽しいElixirスクリプトファイル(my-power.exs)を作ります。

progress_barパッケージをインストールしてプログレスバーを表示させるだけですが色々楽しめるElixirプログラムです。

ターミナル:テスト用のElixirスクリプトを作る
cat <<-'EOF' > ./my-power.exs
Mix.install([{:progress_bar, "~> 3.0"}])

[99..44, 44..77, 77..0]
|> Enum.concat()
|> Enum.each(fn i ->
  ProgressBar.render(i, 100,
    bar: " ",
    bar_color: [IO.ANSI.yellow_background()],
    blank_color: [IO.ANSI.red_background()]
  )

  Process.sleep(22)
end)

IO.puts([])
:ko
EOF

Elixirを実行する環境であれば、この時点でelixirコマンドを用いてElixirスクリプトを直接実行できる所ですが、そうでない場合は実行できません。

ターミナル:Elixirのインストールされていない場合
$ elixir ./my-power.exs
bash: elixir: command not found

elixirコマンドが無い時に代わりに使える./dokodemo-elixir.shを実装します。

ターミナル:elixirコマンドの代わりに使えるシェルスクリプトを作る-1
cat <<-'EOF' > ./dokodemo-elixir.sh
#!/bin/bash

docker run \
  --rm \
  --mount type=bind,src="$(pwd)",dst=/app \
  --workdir /app \
  elixir:1.15.4-otp-25-slim \
  elixir "$@"

echo "完了"
EOF

./dokodemo-elixir.shを実行できるようにファイルのアクセス権を変えます。

ターミナル
chmod +x ./dokodemo-elixir.sh

./dokodemo-elixir.sh./my-power.exsスクリプトを実行。

ターミナル
$ ./dokodemo-elixir.sh ./my-power.exs

:tada::tada::tada:

一回一回コンテナを起動して依存関係をインストールしているのでサクサクとは行かないですが、これでDockerさえインストールされていれば誰でもElixirスクリプトを実行することができるようになりました。

比較的シンプルなElixirスクリプトを共有する場合にこのテクニックが使える場面があるかもしれません。

場合によってはElixir実行環境の有無により分岐をさせても良いかもしれません。

  • Elixir実行環境のある場合
    • elixirコマンドで Elixirスクリプトを実行
  • Elixir実行環境のない場合
    • docker runelixirコンテナを起動してその中で Elixirスクリプトを実行
ターミナル:elixirコマンドの代わりに使えるシェルスクリプトを作る-2
cat <<-'EOF' > ./dokodemo-elixir.sh
#!/bin/bash

if command -v elixir &>/dev/null; then
  echo "elixirコマンドが見つかりました。それを使います。"
  elixir "$@"
else
  echo "elixirコマンドが見つかりませんでした。Dockerを使います。"

  docker run \
    --rm \
    --mount type=bind,src="$(pwd)",dst=/app \
    --workdir /app \
    elixir:1.15.4-otp-25-slim \
    elixir "$@"
fi

echo "完了"
EOF

:tada::tada::tada:

Livebook

いま流行りのLivebookを使ってElixirコードをノートブックとして共有する方法もあります。この方法だとDockerさえも不要になります。

  1. @kikuyuta 先生の「世俗派関数型言語 Elixir を関数型言語風に使ってみたらやっぱり関数型言語みたいだった」より。

11
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
4