やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

「Rubyの起動」を読む

 コマンド引数のうち便利そうなのをピックアップする。

情報源

Rubyの起動

ruby --help
Usage: ruby [switches] [--] [programfile] [arguments]
  -0[octal]       specify record separator (\0, if no argument)
  -a              autosplit mode with -n or -p (splits $_ into $F)
  -c              check syntax only
  -Cdirectory     cd to directory before executing your script
  -d, --debug     set debugging flags (set $DEBUG to true)
  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]
  -Eex[:in], --encoding=ex[:in]
                  specify the default external and internal character encodings
  -Fpattern       split() pattern for autosplit (-a)
  -i[extension]   edit ARGV files in place (make backup if extension supplied)
  -Idirectory     specify $LOAD_PATH directory (may be used more than once)
  -l              enable line ending processing
  -n              assume 'while gets(); ... end' loop around your script
  -p              assume loop like -n but print line also like sed
  -rlibrary       require the library before executing your script
  -s              enable some switch parsing for switches after script name
  -S              look for the script using PATH environment variable
  -v              print the version number, then turn on verbose mode
  -w              turn warnings on for your script
  -W[level=2|:category]
                  set warning level; 0=silence, 1=medium, 2=verbose
  -x[directory]   strip off text before #!ruby line and perhaps cd to directory
  --jit           enable JIT with default options (experimental)
  --jit-[option]  enable JIT with an option (experimental)
  --copyright     print the copyright
  --dump={insns|parsetree|...}[,...]
                  dump debug information. see below for available dump list
  --enable={gems|rubyopt|...}[,...], --disable={gems|rubyopt|...}[,...]
                  enable or disable features. see below for available features
  --external-encoding=encoding, --internal-encoding=encoding
                  specify the default external or internal character encoding
  --verbose       turn on verbose mode and disable script from stdin
  --version       print the version number, then exit
  --help          show this message, -h for short message
  --backtrace-limit=num
                  limit the maximum length of backtrace

Dump List:
  insns           instruction sequences
  yydebug         yydebug of yacc parser generator
  parsetree       AST
  parsetree_with_comment
                  AST with comments

Features:
  gems            rubygems (default: enabled)
  did_you_mean    did_you_mean (default: enabled)
  rubyopt         RUBYOPT environment variable (default: enabled)
  frozen-string-literal
                  freeze all string literals (default: disabled)
  jit             JIT compiler (default: disabled)

Warning categories:
  deprecated      deprecated features
  experimental    experimental features

JIT options (experimental):
  --jit-warnings  Enable printing JIT warnings
  --jit-debug     Enable JIT debugging (very slow), or add cflags if specified
  --jit-wait      Wait until JIT compilation finishes every time (for testing)
  --jit-save-temps
                  Save JIT temporary files in $TMP or /tmp (for testing)
  --jit-verbose=num
                  Print JIT logs of level num or less to stderr (default: 0)
  --jit-max-cache=num
                  Max number of methods to be JIT-ed in a cache (default: 100)
  --jit-min-calls=num
                  Number of calls to trigger JIT (for testing, default: 10000)

-c

 実行せず構文チェックだけする。

ruby -c a.rb

 問題なければSyntax OKと出る。

Syntax OK

 エラーがあればエラー内容を出す。

 でもRubyインタプリタだから実行することではじめてエラーが発覚することがよくある。なので単体テストで全ルートを通すようにしないとバグを残してしまう。そんな感じだから構文チェックだけしたいときなんて、たぶんほとんどない。一応、そういうこともできますよってだけ。

-C <DIR>

  -Cdirectory     cd to directory before executing your script

 ひとつ上の階層にあるa.rbを実行するには以下。

ruby -C../ a.rb

 使いどころがありそうで、よくわからない。以下のように実行したのと同じ状態になる。

ruby ../a.rb
cd ../; ruby a.rb;

 ただ、カレントディレクトリを指定するということは相対パスに影響する。

 たとえばテストコードを書くときに以下のような相対パス参照をすることがある。

require './lib.rb'

 でも、src/test/で同じ階層にしていたら以下のようにしないといけない。

require '../src/lib.rb'

 それを以下のようにできるのだと思う。

ruby -C../src test_lib.rb
require './lib.rb'

 でもそれってシバンに定義したいよね。なので以下のように定義したんだけど。

#!/usr/bin/env ruby -C../src
require './lib.rb'

 実行権限をつけて実行してみると……

chmod +x ./test_lib.rb
./test_lib.rb

 以下のように怒られた。

/usr/bin/env: `ruby -C../src': そのようなファイルやディレクトリはありません
/usr/bin/env: use -[v]S to pass options in shebang lines

 env-Vオプションを渡せばいいっぽい。

#!/usr/bin/env -S ruby -C../src
require './lib.rb'

 実行するとエラー。

$ ./test_lib.rb 
ruby: No such file or directory -- ./test_lib.rb (LoadError)

 なんと、実行した自分自身がみつからないという。

 ですよねー。だってruby -C../srcしちゃったから。カレントディレクトリが移動してしまい、その移動先には実行ファイルがないもんね。

 無駄だろうけど、やり方を変えてみる。

 前回学習したときWikipediaには、Rubyならシェルにみせかけたシバンを書けとあった。なのでそれに-Cオプションを追記した形にしてみる。

#!/bin/sh
# -*- ruby -*-
exec ruby -C../src -x "$0" "$@"
require './lib.rb'
./test_lib.rb
ruby: No such file or directory -- ./test_lib.rb (LoadError)

 同じ結果。ですよねー。

 フルパスで実行すると、また別のエラーになった。

$ /tmp/work/ruby__/test/test_lib.rb
ruby: no Ruby script found in input (LoadError)

 これはよくわからん。

 なんにせよ、せっかく-Cコマンドがあってもやりたいことはできなかった。

 やりたかったのは、以下のようなファイル構成にしつつ、test_lib.rb./test_lib.rbとして実行したらそのファイル単体でテストが実行されるようにしたかった。さらに./rakefileまたはrakeとすれば全テストが実行されるようにしたかった。

  • root/
    • src/
      • lib.rb
    • test/

 現状、これができない。以下のような構成になっており、カレントディレクトリがsrc/直下のときにrakeをすることで全テストできるようになっている。カレントディレクトリが変わったら実行できないし、./test_lib.rb単体での実行もできない。

  • root/
    • src/
    • test/
      • test_lib.rb

 まあいいや。放置で。

 結局-Cの使いどころがわからなかった。

-S

スクリプト名が`/'で始まっていない場合, 環境変数 PATHの値を使ってスクリプトを探すことを指定します。 これは、#!をサポートしていないマシンで、 #! による実行をエミュレートするために、以下のようにして使うことができます:

#!/bin/sh
exec ruby -S -x $0 "$@"
#! ruby

 ちゃんとシバン対策がされているみたい。

-e

 Rubyをインライン実行する。

  -e 'command'    one line of script. Several -e's allowed. Omit [programfile]
ruby -e 'p "Hello Ruby !!"'
ruby -e '7.times {|i| p "Hello Ruby !!"}'

-i

 引数で指定されたファイルの内容を置き換える。sed-i.bakと同じ。

echo matz > /tmp/junk
cat /tmp/junk
ruby -p -i.bak -e '$_.upcase!' /tmp/junk
cat /tmp/junk
cat /tmp/junk.bak
$ echo matz > /tmp/junk
$ cat /tmp/junk
matz
$ ruby -p -i.bak -e '$_.upcase!' /tmp/junk
$ cat /tmp/junk
MATZ
$ cat /tmp/junk.bak
matz

 ついていけないのだが、そもそも$_ってなに? 第一引数かな?

 第一引数はファイル/tmp/junk。これを大文字化しているっぽい。通常ならその結果をstdoutに出して終わる。でも-i.bakすることで同名ファイルに.bakをつけた別ファイルを生成して結果を保存する。つまり結果の出力先をstdoutから.bakファイルに変えた。これは便利かもね。

-l

行末の自動処理を行います。まず、$\$/と同じ値に設定し, printでの出力時に改行を付加するようにします。それから,-nフラグまたは-pフラグが指定されているとgetsで読み込まれた各行の最後に対してString#chomp!を行います。

 String#chomp!をみる。末尾から改行コードを削除するらしい。

 getsは標準入力。

 OSにおけるパス区切文字と改行コードを統一する処理ってことかな?

 それと末尾の改行を消してくれるのは嬉しい。ただ、スペースは消さないのかな? スペースも削除するトリムとは違うのかも。

-n

 プログラム全体が以下でで囲まれているように動作する。

while gets
    ...
end

 REPLのような動作になる。面白いけど、いつ使うかな? 引数だけ変えて何度も動かしたいときに使うんだろうけど。

-p

 -nとほぼ同じ。各ループの最後に変数 $_ の値を出力する。

-s

スクリプト名に続く, -'で始まる引数を解釈して, 同名のグローバル変数に値を設定します。--'なる引数以降は解釈を行ないません。該当する引数は Object::ARGV から取り除かれます。

 Object::ARGで引数を取得するっぽいね。

#! /usr/local/bin/ruby -s
# prints "true" if invoked with `-xyz' switch.
print "true\n" if $xyz

 envシバンで書くと以下のようになるってことかな?

#!/usr/bin/env -S ruby -s
# prints "true" if invoked with `-xyz' switch.
print "true\n" if $xyz

 実行する。

chmod +x ./b.rb
./b.rb -xyz
true

 引数-xyzを渡さないと何も出ない。

./b.rb



 OK! 面白いけど、使わないかな。

所感

 絶対に覚えられない。

対象環境

$ uname -a
Linux raspberrypi 5.10.52-v7l+ #1441 SMP Tue Aug 3 18:11:56 BST 2021 armv7l GNU/Linux