LoginSignup
1
0

More than 3 years have passed since last update.

RustでBash風のaliasをさらに魔改造したalias-exeを作成した

Last updated at Posted at 2020-03-07

alias-exeについて

Rustで作成したシングルバイナリのCUIコマンドで、Windowsにalias相当の機能を提供します。

こちらが基本操作

# 1 hello aliasを作成
> alias edit hello

# 2. 開いたエディタで内容を編集
echo hello $(echo $1)

# 3. 実行
> hello world
hello world

GitHubは wordijp/alias-exe
マニュアルとして README.md と、詳しい仕様についてのドキュメントサイトを用意しています。
バイナリを用意していますが、 scoop.sh 対応ですのでこちらの方がインストールや更新追従も手軽です、aliasはlistディレクトリに作成されますが、こちらのPATHも自動で設定してくれます。

> scoop bucket add wordijp https://github.com/wordijp/scoop-bucket
> scoop install wordijp/alias-exe

機能としては、aliasの登録/更新/削除などの管理機能、実行時に引数処理用の変数($0$1"$@"、etc)、コマンドのネスト($( ... ))の基本に加え、Bash functionのように複数コマンドの実行や、cmd/Bashから欲しい機能を盛り込み、グルーコードとしてmrubyに対応したりなどの結果、魔改造めいたものとなりました。
mrubyは単体では機能が乏しかったため、欲しい機能をRust側で実装して対応しています1

作った経緯

Windowsでalias相当の事をしようとしたらdoskeyコマンドでマクロを登録し、癖が強い2batファイルで頑張るくらいしかありませんでした。
ターミナル環境ではパスや実行環境の差異に悩まされるのでいまいち踏み切れず、そしてつい先月の環境変数のPATHが長すぎてWSL2が突然動かなくなるという一波乱が引き金となり、PATHを短くする為にもalias-exeの作成に踏み切りました。

サンプルコード

aliasとしては冒頭の使い方で十分なのですが、紹介用に他の機能を網羅したコードを記載します、ドキュメントの機能一覧コードそのままですが、以下のような事が出来ます。

まずoverview aliasを作成し

> alias edit overview

内容の編集、この時にVimかnotepadエディタが開きます。

# overview.txt

# command
echo command

# nested command
echo nested $(echo command)

# arguments
echo argc=$# args="$@"

# built-in commands
@set ENV=builtin_set_environment
echo %ENV%

CD
@pushd ..
CD
@popd
CD

# mruby as glue code
```ruby
# this is mruby comment
puts "mruby code"
def add(a, b)
  a + b
end
``` DUMMY
# ↑Qiitaのスタイル崩れ防止のDUMMY、取り除いてください

# nested mruby
echo 2 + 3 = <%= add(2, 3) %>

実行

> overview hoge foo "hello world"
command
nested command
argc=3 args=hoge foo "hello world"
builtin_set_environment
C:\path\to
C:\path
C:\path\to
mruby code
2 + 3 = 5

FizzBuzzを実装してみる

これだけだとなんなので、機能紹介も兼ねて色んな方法でFizzBuzzを実装してみようかと思います。
どれも> fizzbuzz 1 100で実行し、同じ結果になります。


mrubyでオーソドックスにFizzBuzz
# fizzbuzz.txt
```ruby
for i in $1..$2 do
  if i % 15 == 0
    puts 'FizzBuzz'
  elsif i % 3 == 0
    puts 'Fizz'
  elsif i % 5 == 0
    puts 'Buzz'
  else
    puts i
  end
end
``` DUMMY


複数aliasを組み合わせてFizzBuzz

内部用aliasはprivateスコープの意味合いとして _ 始まりにしています。

# _rng.txt
```ruby
for i in $1..$2 do
  puts i
end
``` DUMMY
# _fizzbuzz.txt
```ruby
while s = STDIN.gets
  n = s.to_i
  if n > 0 && n % 15 == 0
    puts "FizzBuzz"
  else
    puts s.chomp
  end
end
``` DUMMY
# _fizz.txt
```ruby
while s = STDIN.gets
  n = s.to_i
  if n > 0 && n % 3 == 0
    puts "Fizz"
  else
    puts s.chomp
  end
end
``` DUMMY
# _buzz.txt
```ruby
while s = STDIN.gets
  n = s.to_i
  if n > 0 && n % 5 == 0
    puts "Buzz"
  else
    puts s.chomp
  end
end
``` DUMMY
# fizzbuzz.txt
_rng $1 $2 | _fizzbuzz | _fizz | _buzz


ネストしまくったFizzBuzz

良く分からないコードになった

# _args.txt

```ruby
def add(a, b)
  a + b
end
def ary(a, b)
  (a..b).to_a
end
``` DUMMY

# 1から100までのruby配列を作成
```ruby
a = [].from_cmd %q( <%= ($(echo $1)..$(echo <%= add($#, 3) %>0)).to_a.to_cmd %> <%= ary(51,$2).to_cmd %> )
``` DUMMY

echo <%= a.to_cmd %>
# _fizzbuzz_args.txt
```ruby
Buzz = 'Buzz'
``` DUMMY

```ruby
for x in ARGV
  x = x.to_i
  s = ((x%3==0)?'$(echo Fizz)':'')+((x%5==0)?<%= Bu$(echo zz)%>:'')
  puts (s!="") ? s : x
end
``` DUMMY
# fizzbuzz.txt
_fizzbuzz_args $(_args $1 $2)

おわりに

alias作成先へのPATHは先頭に追加して優先度を上げた方が使いやすいかとは思いますが、既存コマンドとの名前被りの時に思いもよらないハマりを引き起こしてしまうかもしれません、僕はそれを回避するためにalias名を]hogeと ] 始まりの名前にしています、ほんとは @ 始まりにしたかったのですが実行時に無視されてしまう為、他の押しやすく被らない接頭語を探した結果 ] 始まりとなりました。


  1. STDIN、STDOUT、STDERR、ARGV、cmdとmruby間の変数のやり取りを対応 

  2. しかも「バッチ ジョブを終了しますか (Y/N)?」が煩わしい 

1
0
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
1
0