Sophie

Sophie

distrib > Fedora > 14 > x86_64 > media > updates > by-pkgid > ff948e91b498086e89e1dd0e9ebc6aa0 > files > 17

saphire-3.5.3-1.fc14.i686.rpm

saphire シェル

1.文法

1.0.0 コマンド

    コマンド名 引数1 引数2 ...

    を一つのコマンドを実行します。引数の数は任意です。
    コマンドと引数の区切りにはスペースとタブが使えます。
    実行するコマンドはディスクに保存されたプログラムが使用できます。コマンドを検索するパスには環境変数PATHが使用されます。例えばPATHに/bin:/usr/binが入っていれば(:がPATHの区切りです。例えばprint /home/hoge/bin:/home/hoge2/bin | export PATHなどと設定します。)

    >ls -al

    と実行すると/bin/lsと/usr/bin/lsが検索され先に検索された/bin/lsが実行されます。
    
    引数には慣習的に-で始まるオプション, --で始まるロングオプションがあります。ロングオプションは-lといった一文字のオプションが覚えにくいという理由から覚えやすい--listなどと分かりやすいオプション名で使えるようになったものです。
    引数の書き方としては、lsなど一般的な外部コマンドでは-a -lと二つオプションをつけることと-alと一つのオプションをつけることは同じ意味として処理されます。ただ残念なことにsaphireの組み込みコマンドでは-alは-aと-lとは見なされません。-a -lと分けて書いてください。またオプションに引数を取るコマンドでは一般的に-T 4と書くことと-T4と書くことは同じですが、saphireの組み込みコマンドでは-T 4と書いてください。

1.0.1 標準入力、標準出力、エラー出力とリダイレクト

    一つのコマンドには入力元、出力先、エラー出力先があります。例えばvimという文章編集コマンドを実行しているときは、入力元はキーボード、出力先は画面、エラー出力先も画面です。エラー出力というのはコマンドに不具合があった場合にそれを知らせる特別なメッセージを表示する場所のことです。UNIXではこの入力元や出力先を設定によってファイルに変えることができます。それがリダイレクトです。saphireには以下のリダイレクトがあります。

    > ファイル名             出力をファイルに書き込む
    %2> ファイル名           エラー出力をファイルに書き込む
    >> ファイル名            出力をファイルに追記
    %2>> ファイル名          エラー出力をファイルに追記
    < ファイル名             ファイルを入力としてコマンドに渡す
    %>                       エラー出力を標準出力として扱う(両方標準出力に流す)
    %>>

    例

    puts ファイルに書き込む文字列 > file1

    とするとfile1に「ファイルに書き込む文字列」という文字列が書き込まれます
    
1.0.2 1文

    コマンド1 引数... リダイレクト... | コマンド2 引数... リダイレクト...

    とコマンドを | でつなげたものが一文です。コマンド1の出力先がコマンド2の入力先として扱われて、また、そのコマンド2の出力先が次のコマンドの入力先として扱われ、、、と最後のコマンドまで実行すれば最後のコマンドが画面に出力します。
    これをパイプでつなぐといいます。

    文末には以下の区切りが使えます。

    ;               普通の文の区切り
    改行            普通の文の区切り
    &&              次の文は文のリターンコードが0(実行成功を表す)でないと実行されません
    ||              次の文は文のリターンコードが0以外(実行失敗)でないと実行されません
    &               文をバックグランド実行します

    またコマンド置換の展開は文を単位で行われます。

    saphireでは組み込みコマンドをフィルターの様に使えます。またユーザーが作った関数もフィルターとして使えます。(パイプの途中で内部コマンドやユーザーコマンドが使える)

1.0.3 バックグラウンド処理
    文は&をつけるとバックグランド実行となります。ただし組み込みコマンドやユーザーコマンドの実行は並列的に行うことができません。有効なのは外部コマンドだけです。例えばdefはユーザーコマンドを定義するコマンドですが

    > def fun { sleep 10 }
    > fun &

    はバックグランド実行できません。

    > def fun { sleep 10 & }
    > fun

    は可能です。

    jobsでバックグラウンドや実行中サスペンド(CTRL-Z)したプロセスグループの一覧が見れます。

    fg jobsの一覧の番号

    でそのプロセスグループをフォアグランドに持ってくることができます。

    bg jobsの一覧の番号

    でそのプロセスグループにSIGCONTが送れます。つまり停止したプロセスを再開できます。停止する場面は例えばcpでコピー中にCTRL-Zした場合です。この場合bgするとバックグラウンドでコピーの続きをやってくれます。

    一般的なシェルと違いCTRL-Zでサスペンドさせたりバックグラウンドで実行させたりできるのはパイプの最後が外部コマンドの場合のみです。saphireではパイプの途中でユーザーコマンドをおいたり内部コマンドをおくことができる代わりにこのような制限があります。

1.1 クォート

    クォートとは引用を表し引用符で括るなどとして他の文として解釈されないようにするためのものです。使っている特別な記号を単なる文字列として処理したいときに使います。
    saphireには一文字のクォートとシングルクォートとダブルクォートがあります。一文字のクォートは\で、この後に来た記号や文字はsaphireで特別な意味を失います。例えば行末を表す;はそのままでは行末としてsaphireが処理しますが、\;とすると;はその意味を失い文字列として処理します。クォートは排他的です。別のクォート中はクォートは意味を失います。

    > puts 一つ目の文字列を表示; puts 2つ目の文字列を表示
    一つ目の文字列を表示
    2つ目の文字列を表示

    > puts 一つ目の文字列を表示\; puts 2つ目の文字列を表示
    一つ目の文字列を表示; puts 2つ目の文字列を表示

    \自身を使いたい場合は\\を使います。

    > puts これが\\文字です
    これが\文字です

    シングルクォートは一つ目の'から2つ目の'までを文字列として扱います。

    > puts '一つ目の文字列; puts 二つ目の文字列'
    一つ目の文字列; puts 二つ目の文字列

    ダブルクォートも同じです。

    > puts "一つ目の文字列; puts 二つ目の文字列"
    一つ目の文字列; puts 二つ目の文字列

    > puts "シャア \赤い彗星\ アズナブル"
    シャア \赤い彗星\ アズナブル

    シングルクォートやダブルクォートの違いはダブルクォートは中でコマンド展開を展開する点です。コマンド展開はコマンドの実行結果をコマンドラインに貼り付けることができます。

    > print 赤い彗星 | global futatuna
    > puts "シャア $(global futatuna) アズナブル"
    シャア 赤い彗星 アズナブル

    > print 赤い彗星 | global futatuna
    > puts 'シャア $(global futatuna) アズナブル'
    シャア $(global futatuna) アズナブル

    クォートとクォートの組み合わせですが、全てのクォートは他のクォート内では意味を失います。

    > puts "\aaa"
    \aaa

    > puts '\aaa'
    \aaa

    > puts "'"
    '

    > puts '"'
    "

    > puts \"
    "

    > puts \'
    '

1.2 特殊文字列

    saphireではラインフィールドやキャリッジリターン, タブなどを埋め込めます。
    \n ラインフィールドとして扱う
    \r キャリッジリターンとして扱う
    \t タブとして扱う
    \a ベルとして扱う

    printは文字列を表示するコマンドです。putsと違い最後に改行しません。

    > print 初めまして\nこんにちは\n
    初めまして
    こんにちは

    > print 初めまして\nこんにちは\n
    初めまして
    こんにちは

    > print 初めまして\\nこんにちは\\n
    初めまして\nこんにちは\n

1.2.5 空文字
    
    ''
    ""

    は空の文字列が引数に追加されます。

    > puts "aaaa.c" | sub '\.' ''
    aaaac

1.3.1 変数

    saphireの変数には

    1.ローカル変数
    2.グローバル変数
    3.環境変数
    4.配列
    5.ハッシュ

    の6つがあります。
    ローカル変数、グローバル変数、環境変数はテキスト一行を格納します。

    > ls / | var a  # ローカル変数aにls /の出力から最初の一行を格納
    > ls / | global a # グローバル変数aにls /の出力から最初の一行を格納
    > ls / | export a # 環境変数aにls /の出力から最初の一行を格納

    > ls / | global a b # ls /の出力からグローバル変数aに一行目 bに二行目を格納

    格納したテキストはvar 変数名などとすると取り出せます

    > global a
    bin

    > global a b   # 変数名二つ書くと両方の値を出力
    bin
    etc

    > global a b | global b a # グローバル変数aとbで格納したデータの交換

    > print a | global -p a | global b # -pで代入と出力を同時に行う。グローバル変数aとbにデータ(a)を格納

    配列はテキスト全体を格納します。

    > ls / | ary a  # 配列aにls /の出力全体を格納
    > ls / | ary_add a # 配列aに追記

    格納したテキストはary 変数名とすると取り出せます

    > ary a
    bin
    var
    ....

    またインデックスを使って

    > ary a 0
    bin

    > ary a 0 1
    bin
    var

    と格納している順番(インデックス)の数値を使ってデータを取り出すことができます。インデックスは0より小さい場合最後から数えます。-1で最後の行、-2で最後から2番目の行です。

    複数のインデックスでデータをとりたい場合はlinesを使います

    > ary a | lines 0 0 0 1 
    bin
    bin
    bin
    etc

    範囲指定でとりたい場合は

    > ary a | lines 0..1
    bin
    etc

    です。

    配列にデータを追記するときはary_addを使います

    > ls | ary a; ls | ary_add a   # 配列aにlsの出力2つ分が入る

    ハッシュはテキストの偶数行をキーとして格納して奇数行をアイテムとして格納します。キーを使ってアイテムを取り出すことができます。splitは空白で分解して配列(要素が改行で区切られたテキスト)にするコマンドです。saphireでは複数行のテキストは配列として考えます。

    > split "key1 item1 key2 item2"
    key1
    item1
    key2
    item2

    > split "key1 item1 key2 item2" | hash a
    > hash a key1
    item1
    > hahs a key2
    item2
    > hash a key1 key2
    item1
    item2

    ハッシュにデータを追記するときはhash_addを使います。

    > split "key1 item1 key2 item2" | hash a
    > split "key3 item3" | hash_add a
    > hash a key1 key2
    item1
    item2
    > hash a key3
    item3

    hash 変数名とすると格納されたデータを全て取り出せます

    > hash a
    key2
    item2
    key3
    item3
    key1             # 順番は格納した順とは限らない
    item1

    これとlinesを使ってキーのみやアイテムのみを取り出すことができます

    > hash a | lines \*2
    key1
    key2
    key3

    > hash a | lines \*2+1
    item1
    item2
    item3

    グローバル変数、ハッシュ、配列はshowコマンドで定義状況を見ることができます。

    ローカル変数はスタックフレームを使った変数で

        1. 関数が呼ばれたとき
        2. スクリプトがloadされたとき
        3. クラスが呼ばれたとき

    にスタックフレームが新たに作られ、その後に作ったローカル変数は

        1. 関数が終わるとき
        2. loadされたスクリプトが終わるとき
        3. クラスの実行が終わるとき

    に自動的に消えます。

    > vim a.sa
    def fun { 
        print a | var a 
        var a | pomch    # 関数の中ではaは使える
    }
    fun
    var a | pomch # var a の寿命はfunのなかだけなのでaは空が出力される。ローカル変数は定義されて無い場合空を初期値として代入してからその値を出力します。-nオプションをつければ空の場合は0を出力して初期値を0とします。

    またコマンドラインで新たにコマンドを入力するときにスタックフレームは全て初期化されます。

    > print a | var a   # a の寿命はこのコマンドラインの中でだけ
    > var a | pomch     # aは空なので何も出力されない

    つまりローカル変数はワンライナーの中でだけ有効です。

    ハッシュや配列やグローバル変数は

    sweep 変数名 変数名、、、   # 指定された名前を持つ変数が消される

    sweep # 全部のハッシュや配列、グローバル変数が消されます。

    で消されるまで寿命があります。

    > ls / | global a   # binをグローバル変数aに格納
    > global a | pomch
    bin
    > sweep a
    > global a | pomch   # 消去されたので空が出力される

    ハッシュ、配列、ポインターをローカル変数として使いたい場合は-lオプションを使ってください。

    環境変数は
    sweepで消すことができません。
    またsaphireから起動したプロセスでも生きています。
    アプリケーションの設定として環境変数はよく使われます。

    ローカル変数は初期化せずに使うことができます。
    初期化しない場合空の文字列が出力されます。-nオプションをつけると0で
    初期化されます。

    > var a | add aaa | var a; var a | pomch
    aaa

    > var -n a | + 3 | var a; var a | pomch
    3

    あとローカル変数は
    ++
    --
    というコマンドで+1, -1することができます。
    この場合も初期化する必要がありません。

    > ++ a; var a | pomch
    1

1.3.5 リターンコード(終了コード)

    コマンドを実行したら、そのリターンコードがグローバル変数RCODEに入っています。

    >true; global RCODE | pomch
    0

    >false; global RCODE | pomch
    1

    リターンコードにはコマンド実行中にエラーがあった場合に0以外の数値が入力されます。

    ! 文(コマンド 引数 ... | コマンド ....)

    コマンドを実行してリターンコードを反転する。
    文のリターンコードが0以外ならなら0に0なら1にします。

    > ! puts aaa\nbbb | match -q a; global RCODE | pomch
    1

1.4 コマンド展開

    コマンド展開はコマンドの出力をコマンドラインや文に貼り付けるものです。

    > ls -al $(print main.c)
    は
    > ls -al main.c
    を実行するのと同じです。

    コマンド展開には全部で4種類あります

    1. $(コマンド)
    2. $$(コマンド)
    3. @(コマンド)
    4. @@(コマンド)

    1つ目の$(コマンド)はコマンドの実行結果をsaphireで使用される文字をクォートして貼り付けます。

    > ls -al $(print "*.c")
    は
    > ls -al \*.c
    となります。

    > ls -al $(print "main.c saphire.sa")
    は
    > ls -al main.c\ saphire.sa
    となります。

    2つ目の$$(コマンド)はコマンド結果をそのまま貼り付けます。

    > ls -al $$(print "*.c")
    は
    > ls -al *.c
    となります。

    > ls -al $$(print "main.c saphire.sa")
    は
    > ls -al main.c saphire.sa
    となります。

    3つ目の@(コマンド)はコマンド結果が一つの引数となります。

    > ls -al @(print "main.c")saphire.sa

    は

    ls -alにmain.cという引数とsaphire.saという引数があることになります。

    @(コマンド), @@(コマンド)は実際にはコマンドラインに実行結果を展開しているわけでなく、結果を直接引数としているので高速です。$(コマンド), $$(コマンド)は他の言語で言うと一文が$(),$$()を展開されてからevalされているようなものですが、@(),@@()の場合は字句解析するときにちゃんと字句解析されてます。

    ゆえに big_file.txtが巨大なファイルだとすると

    > print $(cat big_file.txt)

    は$(cat big_file.txt)を展開してから実行するので、何時間も待たされることになりますが

    > print @(cat big_file.txt)

    はそう待たされることが無いでしょう。

    4つ目の@@(コマンド)はコマンド結果が配列であった場合(saphireでは複数行のテキストは配列であると考えます)一つ一つの要素(行)をそれぞれ一引数として実行します。

    > cp @(ls) /tmp
    lsの出力の複数行がすべて一つの引数として展開されエラー

    > cp @@(ls) /tmp
    lsの出力の一行一行がが一つずつ、一つの引数として展開されるのでOK

    > ls | ary a
    > cp @@(ary a) /tmp
    配列の一つ一つの要素が一つの引数としてcpに渡されるのでOK

    @@()に仲間は@@a(), @@m(), @@u(), @@w()があります。
    それぞれ配列の区切りを\a, \r, \n, \r\nとして要素を一つずつ引数にします。

    > ls | ary a
    > cp @@a(ary -La a) /tmp

1.6 グロブ

    カレントディレクトリを基点としてグロブにマッチするファイル名を貼り付けます。

    *                       任意の文字列
    ?                       任意の一文字
    []                      文字列クラス。[abc]ならaかbかcか。[a-z]ならa-z全部。[^a]はa以外。

    > puts [^mM]*
    a a.c aaa autom4te.cache bin conf10097.dir conf11225.dir conf15278.dir conf22554.sh conf9022.dir config.cache config.h config.h.in config.log config.status configure configure.in doc install.sh libsaphire.so.1.0 saphire saphire.c saphire.c.bak saphire.c.bak2 saphire.h saphire.o saphire.sao saphire.sh test.c tmp todo.txt usage.en.txt usage.ja.txt

    カレントディレクトリからm, M以外で始まるファイル名を表示

    注意してほしいのは.*は.から始まるファイル名にマッチしますがbasshなどと違いsaphireでは.と..にはマッチしません。

1.7.1 グローバルパイプ

    最後にコマンド名を書かずにパイプ(|>)で終わるとグローバルパイプに書き込まれます。逆にコマンド名を書かずにパイプ(|>)で始まるとグローバルパイプから読み込まれます。書き込んだ後読み込む前に別の処理を行っても大丈夫です。

    > ls | match -g . | join , |> 
    > lv main.c
    > sleep 10
    > |> less                      # ls | match -g . | join ,の結果がlessされる

    グローバルパイプは何度も読み込めます。
    > echo aaa |>
    > |> print
    aaa
    > |> print
    aaa

    ナンバーグローバルパイプもあります。

    > echo aaa |1>
    > echo bbb |2>
    > |1> print
    aaa
    > |2> print
    bb

    グローバルパイプに追記する場合は

    > echo aaa |>
    > echo bbb |>>
    > |> print
    aaa
    bbb

1.7.1 コンテキストパイプ
    
    コンテキストに応じて入力から読み込みます。
    何度でも読み込むことができます。

    1. サブシェル

    パイプで渡されたデータから読み込みます。

    > split "aaa bbb ccc" | (| print; | print; | sub -g . X)
    aaa
    bbb
    ccc
    aaa
    bbb
    ccc
    XXX
    XXX
    XXX

    2. コマンドライントップ

    標準入力から読み込まれます。

    > | print; | print
    (標準入力から読み込まれて出力)

    3. 関数内

    関数に渡されたパイプのデータから読み込まれます。無いなら標準入力から。

    > def fun {
        | print
        | print
    }

    > print abc | fun
    abc
    abc

    > fun
    標準入力から読み込まれて出力される。

    4. 内部コマンド

    eachは受け取ったテキストを一行ずつ分解してコンテキストパイプに一行を渡して毎行ブロックを実行するコマンドです。

    > ls / | each { | print; | print }
    bin
    bin
    etc
    etc
    ...

    このように内部コマンドではコンテキストパイプを使ったものがあります。

1.7.3 ブロック

    ブロックは中括弧で囲まれた複数のコマンドの塊です。
    ブロックはパーサーによってコンパイルされたものがコマンドに渡されます。
    特定の内部コマンドやユーザーコマンドがブロックを受け取ることができます。
    外部コマンドにブロックを渡しても無視されます。

    > eval { ls }
    main.c sub.c

    > print { ls }
    printはブロックを受け取れないので何も表示しない

    > echo { ls }
    外部コマンドはブロックを受け取れないので何も表示しない

    ユーザー関数でブロックを実行したい場合yeildを使います。

    > def fun { yeild 0; yield 1 }
    > fun { puts a } { puts b}
    a
    b

    yeildの引数の番号に対応したブロックがユーザーコマンドの中で実行されます。

    ブロックには引数が渡せます。引数はブロック開始のすぐ後に
    
    : 変数名 変数名 ... :

    とすることで受け取れます。

    > def fun { yeild 0 data1 }
    > fun { :a: var a | pomch }
    > fun
    data1

1.7.4 改行コード

    改行コードには以下の4つがあります。

    -Lu \n    UNIXの改行コード
    -Lw \r\n  Windowsの改行コード
    -Lm \r    Macの改行コード
    -La \a    saphireオリジナルの改行コード

    saphireは改行コードを配列の区切りとしてみます。

    > split "aaa bbb ccc" | join ,
    aaa,bbb,ccc

    # aaa bbb cccという文字列がsplitで配列(aaa\nbbb\nccc)にされ、joinで区切り文字を,として文字列に戻す

    改行コード自体を配列の要素として使いたい場合は -La, \aを使います。

    > split -La "aaa\nbbb\n ccc\nddd\n eee\nfff" " " | global -La a b c
    > global b
    ccc
    ddd

    split -Laで配列の区切りを\a(ベル)として扱い、文字列を配列にする。(aaa\nbbb\n\accc\nddd\n\aeee\nfff")、そのデータをglobal -La a b cで配列の区切りを\a(ベル)として受け取り、a, b,c という変数に格納する。

    -Laなどの改行コードを扱う(配列を扱う)コマンドには以下があります。

    var, global, export, ary, ary_add,hash,hash_add, split, add, del, join, select, lines, scan, match, read, selector, ssort, printf, each, p

1.7.5 サブシェル

    ()で括ったコマンドを一つのグループとして扱います。saphireのサブシェルは新たにsaphireを実行してそこでコマンドを実行させているわけではありません。新たにプロセスを作ってはいません。

    > (print aaa; print bbb) | more
    aaabbb

    > if( ((true || flase) && true) || false ) { puts yes } | uc
    YES

1.8 制御文

    if文
    if (条件文) {実行文} elif (条件文) {実行文} .... else {実行文}

    > print 1 | var a; if ([ $(var a) = 1 ]) { puts yes } else { puts no } | uc
    YES
    > print 1 | var a; if ([ @(var a) = 1 ]) { puts yes } else { puts no } | uc
    YES
    > print 1 | var a; if (var a | [ = 1 ]) { puts yes } else { puts no } | uc
    YES

    > a=1; vim a.sh
    a.shに以下を入力
    if (var a | [ = 1 ]) {
        puts yes
    } else {
        puts no
    }
    > load a.sh | uc
    YES

    ブロックの中では改行が許されます。

    while文

    while (条件式) {実行文}

    > print 0 | var i; while(var i | [ -lt 3 ]) { var i | pomch; ++ i }
    0
    1
    2

    > vim a.sh
    print 0 | max
    cat main.c | each {
        | length | var len    # コンテキストパイプはmain.cが一行ずつ読み込まれる

        if(var max | [ -lt $(var len) ]) {
            var len | var max
        }
    }

    puts main.cの一行あたりの最大文字数は$(var max)文字です。

    > load a.sh
    main.cの一行あたりの最大文字数は78文字です。

    while文はbreakやCTRL-Cで割り込むことで抜けられます。

    def文

    def 関数名 ブロック

    > def fun { ary -s ARGV|pomch; puts $(ary ARGV 0) $(ary ARGV 1) ; ary ARGV }; fun a b c
    3
    a b
    a
    b
    c

    >vim a.sa
    def fun {
        print 2 | var a
        print 3 | global b
        puts $(var a) $(global b)
    }

    > load a.sa; print 1 | var a; print 2 | global b; (puts $(var a) $(var b); fun; puts $(var a) $(global b)) | less
    1 2
    2 3
    1 3

    関数内では引数はARGVという配列に渡されます。また中で宣言されたローカル変数(varによる宣言やprint 1 | var aなど)は関数から抜けるときに自動的に消えます。

    特殊な構文として引数名を指定することができます。

    > def fun -a _ARGV { puts $(ary -s _ARGV); puts $(ary _ARGV | join ,) }; fun a b c
    3
    a,b,c

    このとき注意してほしいのはこのように引数が指定されたユーザー関数funが呼ばれた時に関数用にスタックは作られないということです。つまりfun内では外のローカル変数にアクセスできますし、fun内で定義したローカル変数は外でも生きています。これはブロックを使ったユーザー定義の制御構文の定義に使用します。

    > vim saphire.sh
    def each -a _ARGV {
        print 1 | var NR
        | while(read |>) {
            yield 0

            ++ NR
        }
    }

   このように定義するとeachに渡すブロックで外で定義されたローカル変数にアクセスできます。

   > print 1 | var a; ls -al | each { |> var line; puts "$(var a):$(var line)"; ++ a }; puts $(var a)

   関数はreturnで戻れます

   self内部コマンドで現在の実行状況を見ることができます。

1.9 ブレース展開
    
    ありません。

2.0 プロセス置換

    <(複文) 

    コマンドの結果をファイルとして扱う

    > cat <(echo aaa) <(echo bbb)
    aaa
    bbb

    > diff <(ls ./etc) <(ls /etc)

    ls ./etcとls /etcの両方の出力がdiffされる

    >(複文)

    ファイルの代わりにブロックを実行する

    > ls | tee >(grep main | less) | less

    ls の結果がlessされてから、ls | grep mainの結果がlessされる

    3.1.5からどちらのプロセス置換もコンパイルされVMで処理されるようになってます。

2.0.1 例外処理

    try { 文 } catch { 例外発生時の処理 }

    文の戻り値が0以外なら catch後のブロックを実行します
    エラーが発生したときもです。

    > try { false; puts aaa } catch { puts bbb }
    bbb

    注意してほしいのはパイプの最後のコマンドの戻り値しか見ないことです。

    > try { false | cat; puts aaa } catch { puts bbb }
    aaa

    エラーが発生した場合はパイプの途中でもcatch以下に移行します。

    > try { fg 10000 | less } catch { puts bbb }
    bbb

2.0.2 ヘアドキュメント

    ソースファイルにテキストを埋め込んで一つのファイルとして扱えます。

    > vim a.sa
    cat <<EOL # <<の後の文字列が文頭に見つかるまで埋め込むテキストとする
    aaa
    bbb
    ccc
    EOL         # ここで終わり

    > load a.sa
    aaa
    bbb
    ccc

    注意してほしいのは文頭に見つかるまでということです。他の言語と違いその文字列が単独である行までではありません。
    これによって以下のようなものが書けます。

    > vim a.sa
    cat <<EOL
    aaa
    bbb
    ccc
    EOL | cat -n

    > load a.sa
    1 aaa
    2 bbb
    3 ccc

    行頭で見つかったらそこでヘアドキュメントを止めるのでコマンドラインの続きが書けます。

    コマンド展開を展開したくない場合は
    終端文字列をシングルクォートで囲ってください。

    > vim a.sa
    print 000 | global a
    cat <<'EOL'
    $(global a)
    aaa
    bbb
    ccc
    EOL

    > load a.sa
    $(global a)
    aaa
    bbb
    ccc

2.0.3 オブジェクト指向

    class内部コマンドでクラスを追加します。

    > vim Student.sa
    class Student {
        | global name age

        def show {
            global name age | printf "name %s\nage %d\n"
        }

        def show2 {
            self->show
        }
    }

    オブジェクトの定義は

    クラス名 オブジェクト名 引数1 引数2 ...

    です。
    
    > load Student
    > split "nobita 12" | Student nobita

    メソッドは

    オブジェクト名->メソッド名

    で呼び出します。

    > nobita->show
    name nobita
    age 12

    クラスは関数呼び出しのようなものでクラスのブロックがオブジェクト定義時(上の例だとStudent nobita呼び出し時)に実行され、オブジェクトにglobal, hash, aryやdefの定義がオブジェクトの属性として追加されていきます。defはメソッドとしてオブジェクトに追加されます。オブジェクトはクラスごとにメソッドの定義を持たずオブジェクト個別にメソッドの定義を持ちます。
    クラス内で外部のグローバル変数にアクセスしたいときはglobal, ary, hashに-gオプションをつけてください。

    クラス内で自分のオブジェクトのメソッドを呼び出したいときは

    self->メソッド名

    を使ってください

    クラスはネストすることができます。

    ネストしたクラスはそのクラスの中と中のネストされたクラスの中でしか呼び出せません。(というか、オブジェクトは親のオブジェクトのクラスを呼び出せる)

    class Parent {
        class Klass {
            def yes {
                puts yes 
            }
        }
        class Child {
            Klass klass
            klass->yes
        }

        Child child
    }

    > Parent parent
    yes

    object 名前1 引数1 引数2 ... { ブロック }

    でクラスで初期化されないオブジェクトを作ることもできます。

    ブロックはあっても無くてもよいです。

    ブロックがあればオブジェクトを引数としてブロックを実行します。ブロックの部分がクラスのようなものです。

    > object a { def yes { puts yes } }; a->yes
    yes

    オブジェクト->class { ブロック } 引数1 引数2...

    オブジェクト->class クラス名 引数1 引数2...

    で後からオブジェクトにメソッドや属性を追加することもできます。

    > object a; a->class { def yes { puts yes } }; a->yes
    yes

    オブジェクトが所有するクラス(や属性)は->class内でしか使用することができません。
    > object a { class Klass { def yes { puts yes } } }
    > a->class { Klass klass; klass->yes }
    yes
    > Klass klass
    エラー

    上のネストしたクラスの例をこれで書くと親オブジェクトのクラスを呼び出せることが分かります。

    > vim a.sa
    object object

    object->class { 
        class Parent {
            def yes {
                puts yes
            }
        }

        object a {
            object a {
                Parent a
                a->a
            }
        }
    }

    > load a.sa
    yes

    また子供のオブジェクトは親のオブジェクトの属性にアクセスできます。

    > class A { print 1 | global a; object a { global a | pomch }; }
    > A a
    1

    inherit でオーバーライドしたクラス、メソッドの元のクラス、メソッドを呼び出せます。

    > vim a.sa
    class A {
        def fun1 {
            puts fun1
        }
    }

    class A {
        inherit;
        
        def fun1 {
            inherit

            puts after 
        }

        def fun2 {
            puts fun2
        }
    }

    > A a; a->fun1; a->fun2
    fun1
    after
    fun2

    class bからclass aを継承したいなら

    > vim a.sa
    class a {
        def fun {
            puts fun
        }
    }

    class b {
        self->class a

        def fun2 {
            puts fun2
        }
    }

    > b b; b->fun; b->fun2
    fun
    fun2

    でいけます。

    オブジェクトをローカル変数として使うには-lオプションをつけてクラスを呼び出すかobjectの引数に-lオプションをつけてください。
    
    > object -l a; a->class { def yes { puts yes } }; a->yes

    > class A { puts A }; A -l a

    メソッドの呼び出し時のオブジェクトの参照順は

    ローカル変数->オブジェクトの属性->グローバル変数となっています。

    グローバル変数のaオブジェクトとローカル変数のaがあるとき

    a->class

    はローカル変数のaのクラスメソッドを呼ぶことになります。

    クラス内でのshowでオブジェクトの属性の定義情報を見れます。-gでグローバル空間で見れます

    クラス内でのsweepでオブジェクトの属性を削除することができます。-gでグローバル空間の変数を消せます。

    classとdefには-overrideオプションを付けることによって上書きすることができます。(この場合は前の定義をinheritで呼び出すことはできなくなる)

    > class A { puts A }
    > class A { inherit ; puts B }
    > A a
    A
    B
    > class -override A { inerit; puts C }
    > A a
    error

2.0.3.2 inherit
    
    inheritでのオーバーライドした関数の呼び出しは内部コマンドでも有効です。つまり

    > def cd { inherit @@(ary ARGV); ls }
    > cd /
    Applications Developer Library Network System Users Volumes bin cores dev etc home lib mach_kernel net opt private sbin tmp usr var
    > pwd
    /

    や

    > def exit { msleep 3; inherit @@(ary ARGV) }
    > exit
    .oO.oO.oO.oO
    exited

2.0.4 リファレンス
    
    > ls | ary a
    > ary -mem a  |ref x
    > ary $x
    lsの出力
    > pwd |ary_add $x
    > ary $x
    lsとpwdの出力

    のような使い方をします。名前で$をつけるとリファレンスのメモリにアクセスできます。

    > ary -mem a | ref
    Array

    とrefだけならメモリに入っているオブジェクトの種別が分かります。

    リファレンスは-lでローカル変数として、クラスの実行内では属性として扱われます。

    関数やクラスもリファレンスとして扱えます。

    > def fun { puts fun }
    > def -mem fun | ref x
    > $x
    fun

    > class Klass { puts Klass }
    > class -mem Klass | ref x
    > $x a
    Klass

    オブジェクトもリファレンスとして扱えます。

    > object a { def yes { puts yes  } }
    > object -mem a | ref x
    > $x->yes
    yes

    名前のアクセス順は
    ローカル変数 -> オブジェクト属性 -> グローバルオブジェクト

    となっています。

    配列、ハッシュ、グローバル、オブジェクト、クラス、関数は-newオプションをつけて生成してリファンスに代入することもできます。

    > ls | ary -new | ref x
    > ary $x
    lsの結果

    > object -new { def yes { puts yes } } | ref y
    > $y->yes
    yes
    

2.0.5 インタラクティブシェル
    
    bashと同じくreadlineを使っているのでbashと同じような使用方法が使えます。特徴としてはmigemoによる日本語ファイル名の補完を行う点です。

    > ls
    UTF8時代だから日本語ファイル名を使おう エフェメラクルツ

    > ls efe[TAB]
    > ls エフェメラクルツ

    と補完されます

    C-xを押すとmacroユーザー関数が実行されます。実行結果がコマンドラインに貼り付けられます。macroユーザーコマンドはsaphire.saで定義されています。macroユーザーコマンドのコンテキストパイプには入力中のインタラクティブシェルのコマンドラインが入ってます。

    実装はreadline.cで行っています。
    
2.0.6 オプション
    -c "コマンド" コマンドの実行
    -rs ランタイムスクリプトをソースファイルとして実行
    -ro ランタイムスクリプトをコンパイル済みファイルとして実行(デフォルト)
    -rn ランタイムスクリプトを実行しない
    -ts ターミナル漢字コードをsjisとする
    -tw ターミナル漢字コードをutf8とする
    -te ターミナル漢字コードをeucjpとする
    -s saphireの漢字コードをsjisとする
    -w saphireの漢字コードをutf8とする
    -e saphireの漢字コードをeucjpとする
    -Lu ラインフィールドの設定をLFとする
    -Lm ラインフィールドの設定をCRとする
    -Lw ラインフィールドの設定をCRLFとする
    --version バージョンを表示する

    bashシェルでsaphireを使うこともできます。

    $ ls | saphire -c '| each { | scan . | each { | add -n 0 X } | join "" | pomch }' | less
    
2.0.7 スクリプトファイルの実行

    saphire スクリプトファイル名
    saphiresh スクリプトファイル名
    
    とすることでスクリプトファイルを実行できます。
    (saphireの方がインタラクティブシェル関連のライブラリをロードしない分速い)
    
    グローバル変数SCRIPT_FILE_NAMEにスクリプトファイル名が入っています。
    配列ARGVに引数が入っています。
    
    スクリプトファイルはUTF8で書かれている必要があります。
    また改行コードはLFで無いといけません。

2.0.8 ユーザーカスタマイズ補完

    completion.saで行っております。ユーザーは~/.saphire/completion.saで行ってください。

    カスタマイズ補完のコマンドは以下です。

    completion コマンド名 .... { ブロック }

    コンテキストパイプには入力中のコマンドラインが入ってます(コマンド 引数1...)の形式で。ブロックの出力のリスト形式(改行区切りのテキスト)が補完候補となります。

2.0.9 ごみ集め

    -newオプションで作られた配列やオブジェクトなどはリファレンスカウントのGCの対象となります。ただし、sweep -gcが実行されるまでメモリに残り続けます。たまにsweep -gcを実行してください。

    > ls | ary -new | ref a
    > ary $a
    main.c
    ....

    > sweep a

    ary -newのオブジェクトがごみとなる

    > sweep -gc
    1 object deleted
    
2.1 組み込みコマンド

    msleep

    sleepと同じく実行を止めます。画面にアニメーションが表示されます。

    true

    リターンコード 0を返します

    false

    リターンコード 1を返します

    [

    -I パイプから入力を受け取って比較

    条件判定式を実行します。詳しくはman [してください。ただしbashなどの[の全ての条件式を実装しているわけではありません。
    saphireの[の特徴としては[ 文字列 -re 正規表現 ]で正規表現の条件式が使えるところです。マッチした場合以下の特殊なローカル変数を使います。

    PREMATCH  マッチした文字列の前の部分が入る
    MATCH マッチした文字列が入る
    POSTMATCH マッチした文字列の後の部分が入る

    数値 グループ化でマッチしたものが前から順番に入ります

    >[ abcdefg -re c ]; var PREMATCH MATCH POSTMATCH | join ,
    ab,c,defg

    グループ化した文字列は対応する数値を変数名に持つ変数に入ります。

    >[ abcdefg -re '(.+)(c)(.+)' ]; var 1 2 3 | join ,
    ab,c,defg

    -reの仲間に下があります

    -rei 大文字小文字区別しない
    -rem 複数行対応
    -reim, -remi 大文字小文字区別しない、複数行対応

    あとsaphireには文字列の大小比較があります。

    -slt

    左側の文字列が小さいなら真

    -sle

    左側の文字列が小さいか等しいなら真

    -sgt

    右側の文字列が大きいなら真

    -sge

    右側の文字列が大きいか等しいなら真

    -silt

    左側の文字列が小さいなら真(大文字小文字は同じ物として扱う)

    -sile

    左側の文字列が小さいか等しいなら真(大文字小文字は同じ物として扱う)

    -sigt

    右側の文字列が大きいなら真(大文字小文字は同じ物として扱う)

    -sige

    右側の文字列が大きいか等しいなら真(大文字小文字は同じ物として扱う)

    =i

    左右の文字列が等しいなら真(大文字小文字は同じものとして扱う)

    ほかにもsaphireの[は文のパイプの2番目以降で実行されるとパイプ入力から文字列を受け取って、その文字列を第一引数として判定することができます。

    >print aaa | [ = aaa ]; global RCODE
    0

    >print aaa | [ ! = aaa ]; global RCODE
    1

    >print aaa | if([ -I = aaa ]) { puts yes } else { no }
    yes

    >print aaa | if(| [ = aaa ]) { puts yes } else { no }
    yes

    この条件式は特別な構文ではなく組み込みコマンドなので書き方に注意してください
    [aaa=aaa]  ->[aaa=aaa]というコマンドは無いのでだめ

    [ aaa=aaa ] -> 第二引数がaaa=aaaとなるのでだめ

    [ aaa = aaa] -> 第3引数がaa]となるのでだめ
    [ aaa = aaa ] -> ok

    index 対象文字列 検索文字列
    index -I 検索したい文字列
    | index 検索したい文字列

    rindex 対象文字列 検索文字列
    rindex -I 検索したい文字列
    | rindex 検索したい文字列

    文字列から検索したい文字列が現れる場所(文字列の先頭からのインデックス)を出力します。文字列のインデックスは0からです。rindexは検索を右から左に行います

    -q 判定だけして出力をしない。リターンコードの値だけを見たいときに使います。

    -nl 出力の最後に改行を加えない

    -I パイプから文字列を受け取る(saphireの組み込みコマンドではパイプの二番目以降にコマンドが実行されると自動的に-Iがついたものとして処理されます)
    -c 数値 検索回数の指定。2が指定されると2回目のマッチした位置が返されます

    -n 数値 文字列の検索開始位置を指定します。
    -b バイト単位で数えたインデックスを返す
    -t ターミナルでの文字列幅で数えたインデックスを返す。
    -i 英字の大文字と小文字を区別しない

    length 文字列
    length -I
    | length 

    文字列の長さを出力します。

    -I 入力された文字列の長さを返します。(パイプの二つ目以降にコマンドがある場合は必要ありません。)
    -nl 改行を出力しません
    -s 文字列のエンコードをSJISとして数えます。
    -e 文字列のエンコードをeucjpとして数えます。
    -w 文字列のエンコードをUTF8として数えます。
    -t ターミナルでの文字列の幅を返します。
    -b バイト数を返します
    -L 改行の数を返す

    uc
    uc -I
    | uc

    文字列を大文字に変換します

    -I 入力された文字列を処理します。(パイプの二つ目以降にコマンドがある場合は必要ありません。)
    -l 改行を出力します。
    -s sjisエンコードとして処理
    -e eucjpエンコードとして処理
    -w utf8エンコードとして処理

    lc
    lc -I
    | lc

    文字列を小文字に変換します

    -I 入力された文字列を処理します。(パイプの二つ目以降にコマンドがある場合は必要ありません。)
    -l 改行を出力します。
    -s sjisエンコードとして処理
    -e eucjpエンコードとして処理
    -w utf8エンコードとして処理

    chomp
    chomp -I
    | chomp

    文字列の最後にある改行を除去します。(LF, CRLF, CRのどれでも対応しています)

    pomch
    | pomch

    文字列の最後に改行が無ければ改行を追加する(LF, CRLF, CRの区別はlinefieldの設定による)

    -Lw CRLFを加える
    -Lu LFを加える
    -Lm CRを加える

    substr 対象文字列 インデックス [カウント]
    substr -I インデックス [カウント]
    | substr インデックス [カウント]

    部分文字列を得ます

    -c 入力をchompして(改行を除去して)から処理します
    -l 最後に改行文字を出力します
    -s 文字列のエンコードをSJISとして数えます。
    -e 文字列のエンコードをeucjpとして数えます。
    -w 文字列のエンコードをUTF8として数えます。
    -b バイトi単位で数えます

    eval ブロック
    | eval

    ブロックを実行します。
    | evalはパイプからデータを読み込んで実行します

    fg ジョブ番号

    ジョブ番号のジョブをフォアグランドグループにします。(前面に持ってくる)
    bg ジョブ番号

    ジョブ番号のジョブにSIGCONTを送ります。バックグラウンドのまま実行を再開します。

    jobs

    ジョブの一覧を表示します。

    rehash

    コマンドライン補完のコマンド名の一覧のキャッシュを更新します。新しいプログラムがインストールされたらrehashを実行すると、そのプログラムの補完が有効になります。

    kanjicode [-s|-e|-w]

    -s saphireが処理する漢字コードをSJISとして設定します
    -e saphireが処理する漢字コードをEUCJPとして設定します
    -w saphireが処理する漢字コードをUTF8として設定します
    -q 実行結果を出力しません

    saphireが処理する漢字コードというのは具体的には変数や配列の添え字の数え方や文字の数え方に関連する内部関数の-s,-e,-wを指定しない場合のデフォルトの文字コードということです

    linefield [-Lw|-Lm|-Lu]

    -Lw saphireが処理する改行コードをCRLFとして処理します
    -Lm saphireが処理する改行コードをCRとして処理します
    -Lu saphireが処理する改行コードをLFとして処理します
    -q 実行結果を出力しません

    saphireが処理する改行コードというのは組み込みコマンドがパイプによって文字列を一行受け取る場合の改行コードです。ほかにもjoinやsplitなど組み込みコマンドの処理で使われます。

    var 変数名 変数名

    ローカル変数の出力
    変数がまだ代入されていない場合は空文字列を代入して出力する。まだ代入されてなくて-nが指定された場合0を代入して出力する。

    var -I 変数名 変数名...
    | var 変数名 変数名...

    各変数名に入力から一行ずつ受け取って、chompして一行を各変数名に代入します

    > print aaa\nbbb | var a b; var a b | join ,
    aaa,bbb

    -ncオプションでchompせずに改行コードも一緒に変数に代入します
    -f 区切り文字(複数可能) 区切り文字列を改行でなく別のものに設定します。
    -I 入力から文字列を受け取り変数に設定する
    -p 出力を行う
    -n 代入されていなくて出力されたら初期値を0とする
    -l 出力の最後に改行を追加
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -shift 入力で取った値の残りを出力

    global 変数名 変数名

    グローバル変数の出力
    変数がまだ代入されていない場合は空文字列を代入して出力する。まだ代入されてなくて-nが指定された場合0を代入して出力する。

    global -I 変数名 変数名
    | global 変数名 変数名...

    各変数名に入力から一行ずつ受け取って、chompして一行を各変数名に代入します
    -nc オプションでchompせずに改行コードも一緒に変数に代入します
    -f 区切り文字(複数可能) 区切り文字列を改行でなく別のものに設定します。
    -nc 改行をchompせずに変数に代入する
    -I 入力から文字列を受け取り変数に設定する
    -p 出力を行う
    -l 出力の最後に改行を追加
    -n 代入されていなくて参照されたら初期値を0とする
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -shift 入力で取った値の残りを出力

    > ls | global -shift a b | ary a

    export 変数名 変数名

    環境変数の参照
    変数がまだ代入されていない場合は空文字列を代入して出力する。まだ代入されてなくて-nが指定された場合0を代入して出力する。

    export -I 変数名 変数名
    | export 変数名 変数名...

    各変数名に入力から一行ずつ受け取って、chompして一行を各変数名に代入します
    -ncオプションでchompせずに改行コードも一緒に変数に代入します
    -l 出力の最後に改行を追加
    -nc 改行をchompせずに変数に代入する
    -I 入力から文字列を受け取り変数に設定する
    -p 出力を行う
    -n 代入されていなくて参照されたら初期値を0とする
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    print 出力文字列
    print -I
    | print

    -l 文字列の最後に改行文字を追加する
    -I 入力を受け取って出力する
    -f 区切り文字を設定する

    puts 出力文字列
    puts -I
    | puts

    -I 入力を受け取って出力する
    -f 区切り文字を設定する

    compile ファイル名

    saphireのスクリプトをコンパイルしてコンパイル結果をファイル名.saoとして出力する

    load ファイル名

    saphireのスクリプトを読み込み実行する

    -sao コンパイル済みのスクリプトファイルを読み込み実行する

    exit

    -f ジョブがあっても強制的に終了する

    saphireを終了する

    split -I [区切り文字の正規表現]

    split 文字列 [区切り文字の正規表現]

    文字列を区切り文字の正規表現で区切って区切りを改行として出力する
    区切り文字が省略されると\s+が渡される

    | split [区切り文字の正規表現]

    入力を受け取り区切り文字で区切って区切りを改行として出力する
    (文字列を区切り文字で区切って配列にする)

    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -I パイプから入力を得る
    -m 複数行対応
    -i 大文字小文字無視
    -s 文字列のエンコードをSJISとして数えます。
    -e 文字列のエンコードをeucjpとして数えます。
    -w 文字列のエンコードをUTF8として数えます。

    >split "aaa bbb ccc"
    aaa
    bbb
    ccc

    >split "aaa,bbb,ccc" ,
    aaa
    bbb
    ccc

    >print aaa bbb ccc | split
    aaa
    bbb
    ccc

    >print aaa,bbb,ccc | split ,
    aaa
    bbb
    ccc

    >ls | chomp | split -f , -m | pomch
    main.c,test.c,Makefile,configure.in

    | add 文字列 文字列 ...
    | add { ブロック } { ブロック } ...

    パイプに文字列を追加する

    -n インデックス インデックス番目に文字列を追加する
    -L 行数 行数のところに文字列を追加する(0なら1行目)
    -s 文字列のエンコードをSJISとして数えます。
    -e 文字列のエンコードをeucjpとして数えます。
    -w 文字列のエンコードをUTF8として数えます。
    -b -nのインデックスをバイト単位で数えます
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    > print aaa | add ccc\n
    aaaccc

    > puts abc | add -n -2 { print d }
    abcd

    > puts アンディ\nエフェメラ\nタッタ | add -L 1 @(puts アード)
    アンディ
    アード
    エフェメラ
    タッタ

    > puts アンディ\nエフェメラ\nタッタ | add -L 1 {puts アード}
    アンディ
    アード
    エフェメラ
    タッタ

    del
    del 文字数
    del -n インデックス 文字数

    文字数分パイプの文字列を末尾から削除する

    -n 末尾からではなくてインデックスから文字列を削除する
    -s 文字列のエンコードをSJISとして数えます。
    -e 文字列のエンコードをeucjpとして数えます。
    -w 文字列のエンコードをUTF8として数えます。
    -b -nのインデックスをバイトi単位で数えます
    -L 行数 行数行を削除
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    >print abcdE | del 
    abcd

    >print aaa\nbbb\nccc\nddd\neee | del -L 2 2
    aaa
    bbb
    eee

    join -I [区切り文字列]
    join 文字列 [区切り文字列]
    | join [区切り文字列]

    改行区切りの文字列に文字列を間に挟んでつなげる
    (配列を区切り文字を挟んで一行にする)

    >ls saphire* | join , | del | add \n
    saphire,saphire.c,saphire.c.bak,saphire.h,saphire.sao,saphire.ksh,saphire.o

    -q 区切り文字以外にsaphireの特殊文字にクォートを施します。
    -Q 区切り文字以外にbashの特殊文字にクォートを施します。
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    >print "aaa aaa\nbbb bbb" | join -q
    aaa\ aaa bbb\ bbb

    > touch $$(print "aaa aaa\nbbb bbb" | join -q)
    aaa aaaというファイルとbbb bbbというファイルが作られる

    x 文字列 個数

    文字列を個数分出力します

    | x 個数

    パイプからの入力文字列を個数分出力します

    > print a | x 5 | pomch
    aaaaa

    | lines 行数 (ブロック)...

    入力から受け取り指定された行数の行を表示
    ブロックがあれば、各行がコンテキストパイプに入れられて
    ブロックが実行される

    -r 行を反転して表示する
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    行数には

    x以外で始まる英字 次のブロックを実行するだけ

    数字 その行番号

    数字..数字 範囲指定

    \*数字1+数字2 y = 数字1*x + 数字2 [x=1,2,3...] のyにあたる行

    (lines \*2+1 --> 奇数の行)
    (lines \*2 --> 偶数の行)

    +数字2は省略すると0となる

    x数字1+数字2 y = 数値2から数字1個ずつ得る

    が使えます。

    +数字2は省略すると0となる

    行数の最後にbをつけるとブロックは指定された全ての毎行に対してブロックを実行します。


    >print aaa\nbbb\nccc | lines 0 0..1
    aaa
    aaa
    bbb

    >puts aaa\nbbb\nccc | lines -r
    ccc
    bbb
    aaa

    >print aaa\nbbb\nccc | lines BEGIN { puts first } 0 1..0 END { puts last }
    first
    aaa
    bbb
    aaa
    last

    >print aaa\nbbb\nccc\nddd | lines 0 { | uc } 1 { | sub -g . D } 2..-1
    AAA
    DDD
    ccc
    ddd

    >ls | lines 0 { | var a } 1..-1b { | var -a b }

    aに1行目が
    bに最後の行が入ります

    >ls | lines 0 { | var a } 1..-1 { | var -a b }

    aに1行目が
    bに2行目以降が入ります

    > times 15 { :i: ++ i; puts i } | lines x5 { | join , }
    1,2,3,4,5
    6,7,8,9,10
    11,12,13,14,15

    | select 条件式

    条件式を成り立つ場合その行を出力

    >print aaa\nbbb\nccc | select { | [ -re ^a ] }
    aaa
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    | rows 数値 [-b|-B] (ブロック)

    -s 文字列のエンコードをSJISとして扱いインデックスを数えます。
    -e 文字列のエンコードをeucjpとして扱いインデックスを数えます。
    -w 文字列のエンコードをUTF8として扱いインデックスを数えます。
    -r 文字列を逆順にして出力する

    x以外で始まる英字 次のブロックを実行する

    数字 その文字インデックス
    数字..数字 文字インデックス範囲

    \*数字1+数字2 y = 数字1*x + 数字2 [x=1,2,3...] のyにあたる文字
    +数字2は省略すると0となります。

    (rows \*2+1 --> 奇数の文字)
    (rows \*2 --> 偶数の文字)

    x数字1+数字2 y = 数値2から数字1個ずつ得る

    が使えます。

    +数字2は省略すると0となります。

    数字の最後にbをつけると,ブロックは指定された全ての毎文字に対してブロックを実行します。

    パイプで渡された各文字ごとにブロックを実行するか
    ブロックが無ければ表示する

    > print abcdefg | rows BEGIN { puts first } 0 3 { | puts } END { puts last }
    first
    ad
    last

    > print abcdefg | rows 0 { | uc } 1..-1 { | puts }
    Abcdefg

    > print abcdefg | rows 0 { | uc } 1..-1 { | puts }
    Ab
    c
    d
    e
    f
    g

    > print abcdefg | rows -r |pomch
    gfedcba

    ary 配列名 要素1 要素2 .....
    配列を出力

    ary -I
    | ary 配列名

    入力から各行を1要素として配列に代入(各行はchompされる)

    -s 配列のサイズを出力する
    -nc 1行を1要素として配列に代入する場合chompしない
    -I 入力を受け取り配列の要素として代入する
    -p 代入しつつ出力もする
    -l 出力に改行をつける
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -l ローカル変数として扱う

    ary_add -I 配列名
    | ary_add 配列名

    入力から各行を1要素として配列に追加する(末尾)

    | ary_add -n インデックス 配列名

    インデックスの場所に要素を追加する

    -n 数値 数値のところにインサート
    -nc chompしない
    -p 出力を行う
    -l 出力に改行をつける
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -l ローカル変数として扱う

    ary_erase 配列名 インデックス

    -l ローカル変数として扱う

    配列の要素を削除

    match

    正規表現の比較演算子

    match -I [正規表現] -> パイプ入力を[正規表現]で比較
    コマンド | match [正規表現] -> コマンドの出力全てを[正規表現]で比較
    match [文字列] [正規表現] -> [文字列]を[正規表現]で比較
    コマンド | match -L [正規表現] -> grepの様に各行に正規表現がマッチするか比較する。
    コマンド | match -g [正規表現] -> コマンドの出力全てを[正規表現]で比較。マッチしても止まらず何度も比較を繰り返す
    match -g [文字列] [正規表現] -> [文字列]を[正規表現]で比較。マッチしても何度も比較を繰り返す

    -q 出力しない
    -nl 出力を改行しない
    -n 行番号をつける
    -I パイプ入力から比較する文字列を受け取る。コマンドの2つ目からは自動的に-Iがあるとみなす
    -f [文字列] グループ化のマッチした文字列の出力の区切りに[文字列]を使う。デフォルトはタブ
    -g グローバル。一文字ずつ比較する
    -L 行指向比較。一行ずつ比較する。grepと似た動きをする。
    -i 正規表現が大文字と小文字を区別しない
    -m 複数行マッチする
    -s sjisエンコードとして処理
    -e eucjpエンコードとして処理
    -w utf8エンコードとして処理
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    PREMATCH マッチした前の部分
    MATCH マッチした部分
    POSTMATCH マッチした後の部分

    MATCH_COUNT マッチした回数

    数値 グループ化でマッチしたものが前から順番に入ります

    >ls | match -L -n minato_curses
    11:minato_curses.c
    12:minato_curses.o
    13:minato_curses.h

    (行指向)

    >ls | match .
    A

    (一文字ヒットしたら以後比較しない)

    >ls | match -g .
    A
    U
    T
    H
    O
    R
    S

    >print 'file:123' | match '(.+?):(\d+)'
    file	123

    >print 'file:123' | match -f \n '(.+?):(\d+)'
    file
    123

    >print abcdef | match '..(.).(.).'; var 1 2 | join ,
    c	e
    c,e

    >puts mikan | match -f , '(m)i(kan)'
    m,kan

    matchはegrepと違ってマッチした行ではなくてマッチした部分を出力します。
    egrepのように行指向で処理を行いたい場合は-Lをつけてください。
    またグループ化した場合はそのグループ化してマッチした部分をフィールド区切りで出力します。(フィールドの初期値はタブ)

    >puts "file:123" | match '(.+?):(\d+)'
    file	123

    matchは一行ごとに処理はしません。受け取った文字列全てに検索を行います。(デフォルトでは検索回数は1回だけ。-gで何回も)
    一行ごとに処理したい場合はeachなどと組み合わせてください

    > ls | each { | match -q -i m && | print }
    Makefile
    Makefile.in
    README.ja.txt
    autom4te.cache
    gmon.out.hayai
    gmon.out.osoi
    saphire_commands.c
    saphire_commands.o
    saphire_main.c
    saphire_main.o
    saphire_vm.c
    saphire_vm.o
    main.c

    scan 文字列 正規表現
    | scan 正規表現

    内部的にはmatch -g と同じです。

    [文字列]を[正規表現]で比較。マッチしても何度も比較を繰り返す

    -I パイプから比較する文字列を受け取る。コマンドの2つ目からは自動的に-Iがあるとみなす
    -f [文字列] グループ化のマッチした文字列の出力の区切りに[文字列]を使う。デフォルトはタブ
    -i 正規表現が大文字と小文字を区別しない
    -m 複数行マッチする
    -s sjisエンコードとして処理
    -e eucjpエンコードとして処理
    -w utf8エンコードとして処理
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    MATCH_COUNT マッチした回数がローカル変数に入る

    数値 グループ化でマッチしたものが前から順番に入ります

    >ls | scan .
    A
    U
    T
    H
    O
    R
    S

    scan 正規表現 { ブロック }

    マッチするごとにブロックが実行されます。コンテキストパイプにマッチした文字列が入ってます。ただし一文字ごとにブロックを起動するのはパフォーマンス的に我慢なら無いレベルだと思っていてください。

    > print aaaa123-bbb1234 | scan '\d+' { | x 2 | pomch }
    123123
    12341234

    > cat big_file.txt | scan . { | print }
    固まる。多分一日中。

    MATCH_COUNT マッチした回数が入るローカル変数

    erase 文字列 正規表現
    | erase 正規表現

    正規表現にマッチする部分を文字列から削除する
    グループ化した場合はマッチする部分のうちグループ化された部分だけ文字列を削除する

    -g 何度も正規表現を繰り返す
    -m 複数行対応
    -i 大文字小文字無視
    -s sjisエンコードとして処理
    -e eucjpエンコードとして処理
    -w utf8エンコードとして処理
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    > erase abcdefg\n .
    bcdefg

    > erase abcdefg\n '.$'
    abcdef

    > puts abcdefg | erase '(.).(.)$'
    abcdf

    sub 文字列 正規表現 変換後の文字列
    | sub 正規表現 変換後の文字列

    subは文字列の変換を行います。

    >ls
    saphire_vm.c
    saphire_vm.o
    libsaphire.so
    libsaphire.so.1
    libsaphire.so.1.0
    main.c
    readline.c
    readline.o

    >ls | sub a A
    sAphire_vm.c
    saphire_vm.o
    libsaphire.so
    libsaphire.so.1
    libsaphire.so.1.0
    main.c
    readline.c
    readline.o

    >ls | each{ | sub a A }
    sAphire_vm.c
    sAphire_vm.o
    libsAphire.so
    libsAphire.so.1
    libsAphire.so.1.0
    mAin.c
    reAdline.c
    reAdline.o

    > sub -g aaa a x | pomch
    xxx

    グループ化した文字列は\1,\2,...に入ります。変換後の文字列で
    \1,\2を使うとグループ化した文字列が入ります。
    変換後の文字列に\自身を使いたい場合は\\を使ってください

    > print mikan | sub '(.)i(...)' '\1\2'
    mkan

    変換は一回しか行いません。-gをつけると何回も行ってくれます。

    -g グローバル。一行に二度以上マッチしていたら、2度以上変換を行います
    -q 出力を表示しない
    -i 大文字と小文字を区別しない 
    -m 行をまたいだ正規表現
    -c 変換前にチェックする
    -s sjisエンコードとして処理
    -e eucjpエンコードとして処理
    -w utf8エンコードとして処理
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    マッチした回数はローカル変数SUB_COUNTに入ります。

    sub 正規表現 { ブロック } 

    マッチした文字列をコンテキストパイプにいれてマッチした地点でブロックを実行します。出力が変換結果となります。

    > print abcdb | sub -g b { | uc } | pomch
    aBcdB

    sub 正規表現(グループ化) { ブロック } 

    マッチした文字列をコンテキストパイプにいれてマッチした地点でブロックを実行します。出力が変換結果となります。グループ化した文字列はローカル変数に入ってます。

    > print abcdbcgg | sub -g '(.)(.)' { var a b | join , | chomp } | pomch
    a,bc,db,cg,g

    read

    -a すべてを読み込む
    -n 数字 数字行読み込む
    -p 読み込んでも読み込んだ分のバッファを消さない
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    readはコンテキストに応じた入力から一行読み込む。もう一度読み込むと続きから読み込む。全てを読み込むとリターンコード1を返す。

    > puts aaa\nbbbb | read
    aaa

    > puts aaa\nbbb | (read | chomp | add D\n; read | chomp | add E\n)
    aaaD
    bbbE

    > puts aaa\nbbb | read -a
    aaa
    bbb

    > puts aaa\nbbb\nccc\neee\nfff | (read; read -n 2 | cat -n; read -a)
    aaa
          1 bbb
          2 ccc
    eee
    fff

    > puts aaa\nbbb\nccc | (read -a -p; read -a -p)
    aaa
    bbb
    ccc
    aaa
    bbb
    ccc

    read ファイル名

    ファイル名のファイルから一行読み込む。
    EOFに達すると1を返しcloseされる。
    ファイルはsaphireの終了時にcloseされる
    closeコマンドで閉じることもできる

    -n 数値 数値行読み込む
    -a 全て読み込む

    close ファイル名
    close -a

    readで開いたファイルを閉じる
    -aは開いたファイル全てを閉じる

    cd ディレクトリ

    ディレクトリに移動する。PWDに現在のカレントディレクトリが入る

    cdだけだとHOMEに移動する

    | selector

    入力から読み込んだテキストからユーザーが一行または複数行選択して選択した行を出力する

    ENTERで決定
    SPACEで複数選択
    aで全マーク反転

    データのエンコーディングはUTF8のみしか対応していません。

    -r 前回のカーソル位置、スクロールトップ位置を使用する。
    -c カーソル位置 カーソル位置を設定する
    -t スクロールトップ位置 スクロールトップ位置を設定する
    -m 複数行の選択を許す。スペースで複数行選択できる
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    max 数値1 数値2

    大きいほうの数値を出力する

    -nl 出力の最後に改行を加えない

    min 数値1 数値2

    小さいほうの数値を出力する

    -nl 出力の最後に改行を加えない

    extname ファイル名

    -I 入力をパイプから受け付ける
    -nl 出力の最後に改行を加えない

    拡張子を出力する

    parentname ファイル名

    -I 入力をパイプから受け付ける
    -nl 出力の最後に改行を加えない

    ディレクトリ名のみ出力する

    noextname ファイル名

    -I 入力をパイプから受け付ける
    -nl 出力の最後に改行を加えない

    拡張子以外のファイル名を出力する

    raise メッセージ

    メッセージをエラーメッセージに入れて実行を停止する

    hash 連想配列名 キー1 キー2 ...

    連想配列の内容を出力する
    キーが無ければ全て出力する

    | hash 連想配列名
    hash -I 連想配列名

    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -l ローカル変数として扱う
    -p 代入しつつ出力もする

    パイプ入力から連想配列のデータを受け取って連想配列を作る

    > split "key value key2 value2 key3 value3" | hash a
    > hash a key
    value

    | hash_add 連想配列名

    > split "key value" | hash_add a

    連想配列にデータを追加する

    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う
    -l ローカル変数として扱う
    -p 代入しつつ出力もする

    hash_erase 連想配列名 キー

    -l ローカル変数として扱う

    連想配列の要素を削除する

    sweep

    全てのグローバル変数、連想配列、配列、オブジェクト、ポインターを消す
    クラス内ではオブジェクトの属性を消す

    -reg 正規表現のキャッシュを消す
    -f 関数定義をクリアする
    -c クラス定義をクリアする
    -gp グローバルパイプの内容を消す
    -g グローバルの定義を消す

    引数に変数名を書くとその変数だけ消す

    sweep A   # A だけ消す

    show

    全てのグローバル変数、連想配列、配列の定義情報を見る
    オブジェクト内では属性が見れる

    -v グローバル変数の値も表示する
    -g オブジェクト内でもグローバルの定義情報を見る

    printf フォーマット 引数1 引数2 ...
    | printf フォーマット

    -l 改行を最後に出力する
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    フォーマットはC言語と同じです。

    > printf "%10s,%10s\n" abcdefg abcdefg
       abcdefg,   abcdefg

    > ls | printf "[%s], [%s], [%s]\n[%s], [%s], [%s]\n"
    [AUTHORS], [saphire_commands.c], [saphire_curses.c]
    [saphire_debug.c], [saphire_extra.c], [saphire_hash.c]

    配列をパイプから受け取るとそれぞれの要素が引数となる

    | ssort
    | ssort ブロック

    一行ごとのソート。

    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    ブロックを省略すると { | var a b; [ $(var a) -slt $(var b) ] }が渡される

    コンテキストパイプの一行目に左の一行が入っている
    コンテキストパイプの二行目に右の一行が入っている

    > ls | ssort
    > ls | ssort { |var a b; [ $(var a) -slt $(var b) ] }

    lsの出力を行ごとに昇順に並び替える

    > ls | ssort { |var a b; [ $(var a) -sgt $(var b) ] }

    lsの出力を行ごとに降順に並び替える

    > ary ARGV | ssort { | var a b ;[ $(var a) -slt $(var b) ] } | ary ARGV2
    ARGVを昇順にソートしてARGV2に代入

    > ls -al | ssort { | each { | split | lines 4 } | var a b; [ $(var a) -lt $(var b) ] }
    5フィールド目でソート

    ++ ローカル変数名

    ローカル変数の値を1増やす
    ローカル変数が存在しなければ1が入ったローカル変数を作成する

    | ++
    パイプから入力を受け取り1増やして出力する

    -- ローカル変数名
    ローカル変数の値を1減らす
    ローカル変数が存在しなければー1が入ったローカル変数を作成する

    | --
    パイプから入力を受け取り1減らして出力する

    | + 数字
    パイプから入力を受け取り数字で加算して出力する

    | - 数字
    パイプから入力を受け取り数字で減算して出力する

    | \* 数字
    パイプから入力を受け取り数字で乗算して出力する

    | / 数字
    パイプから入力を受け取り数字で除算して出力する

    | mod 数字
    パイプから入力を受け取り数字で除算して、余りを出力する

    | pow 数字
    パイプから入力を受け取り数字乗して出力する

    range 数字1 数字2

    数字1から数字2までの範囲の数字を作成

    > range 1 5
    1
    2
    3
    4
    5

    pcat ブロック ブロック ....

    複数のブロックの出力結果をパイプに流す

    > pcat { echo aaa } { puts bbb } | less
    aaa
    bbb

    | ptee ブロック ブロック ....

    パイプで受け取った入力を複数のブロックに渡す
    受け取ったデータはコンテキストパイプに入っています

    >puts aaa | ptee { | cat } { | print } { | sub -g a b }
    aaa
    aaa
    bbb

    ネストも可能

    > puts aaa | ptee { | cat } { | ptee { | print } { | print } } | less
    aaa
    aaa
    aaa

    return 数値

    第一引数を終了コードとして関数から復帰する
    数値を省略すると終了コードが0となる

    each { block }

    毎行に一回ブロックを実行する。コンテキストパイプにその行が入っている

    >ls | each { | print }
    main.c
    sub.c

    ブロックに引数を持たすと行番号が得られます。

    > ls | each { :i: | print | add -n 0 $(var i) }
    0:main.c
    1:sub.c

    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    foreach 文字列...文字列 ブロック

    並べられた文字列毎にブロックを実行する。文字列はコンテキストパイプに入っている。

    >foreach a b c { | pomch }
    a
    b
    c

    >print a\nb\nc | ary A
    >foreach $(ary A | join " ") { | pomch }
    a
    b
    c

    >print a\nb\nc | ary A
    >foreach @@(ary A) { | pomch }
    a
    b
    c

    | p

    デバッグ用の何もしないフィルタ。
    パイプの内容を見ることができます。
    データのエンコーディングはUTF8しか対応していません。

    SPACE, RETURNが押されたら次のコマンドにデータを流します。
    ESCAPE, CTRL-C, qが押されたらエラーを出して処理を止めます

    -c カーソル位置 カーソル位置を設定する
    -t スクロールトップ位置 スクロールトップ位置を設定する
    -Lu 改行コードをLFとして扱う
    -Lm 改行コードをCRとして扱う
    -Lw 改行コードをCRLFとして扱う
    -La 改行コードを\aとして扱う

    envspace 環境変数名=値 環境変数名2=値2 ... { ブロック }

    環境変数を一時的に値を設定してブロックを実行。

    > envspace LANG=c { date }
    LANG=cでのdateの実行結果

    quote 文字列
    | quote

    特殊文字列にクォートを施して出力します。

    -b bashでの特殊文字列をクォートする

    > puts $$(print "<>" | quote)
    <>

    self

    関数やクラスの実行状況が分かります。
    Running Function Info
    のinputはパイプからデータを受けているか受けていないかという意味です。

    def

    関数を定義する

    -a [引数] 引数を設定する
    -A 引数の情報を出力、入力する。

    > print "puts a" | def fun
    > print _ARGV | def -A fun # 引数情報を設定
    > def fun
    puts a
    > def -A fun
    _ARGV
    > fun
    a
    > def fun { puts b }
    > fun
    b

    class

    クラスを定義する

    > print "puts yes; puts yes" | class a
    > a a
    yes
    yes
    > class a
    puts yes; puts yes
    > class b { puts b }
    > b b
    b

    fselector

    ファイルを選択して選択されたファイルを出力する。

    -m 複数選択可

    ファイル選択メニューでの操作は

    SPACE ファイル選択 
    TAB,W 選択したファイルをコマンドラインに挿入
    BackSpace 親ディレクトリに移動
    Return ディレクトリ選択時そのディレクトリに移動

saphireインタラクティブシェルで有効なコマンド

    history

    コマンドラインヒストリーの一覧を出力する

    add_history

    引数一つかパイプから一行取ってコマンドラインヒストリーに追加。

    write_history

    メモリ上のヒストリーをファイルに書き込む

    read_history

    ファイルのヒストリーをメモリに読み込む

    clear_history

    ヒストリーをクリア

    remove_history (数値)

    引数のインデックスのヒストリーを削除

saphire.saで定義されているユーザー関数

    shift ブロック

    一行目をコンテキストパイプに入れてブロックを実行。その他を出力

    times 回数 ブロック

    回数分ブロックを実行します

    コンテキストパイプに回数のデータが入ります。

    > times 3 { | pomch }
    0
    1
    2

    step 初期値 終了値 増分 ブロック

    >step 3 10 3 { | pomch }
    3
    6
    9

    shelp

    使い方を見る

    smake

    makeの実行結果から一行選んで、その行をエディッターで起動する

    sgrep

    grepの実行結果から一行選んで、その行をエディッターで起動する

    case value regex1 block1 regex2 block2...

    >a=1; case $(var a) 0 { puts a } 1 { puts b } 2 { puts c } 3 { puts d }
    b

    for 変数 in 文字列 文字列.... ブロック

    並べられた文字列をひとつずつ変数に入れてブロックを実行する。

    >for a in a b c { puts @(var a) }
    a
    b
    c

    >print a\nb\nc | ary A
    >for a in $(ary A | join " ") { puts @(var a) }
    a
    b
    c

    >print a\nb\nc | ary A
    >for a in @@(ary A) { puts @(var a) }
    a
    b
    c

    time { ブロック }

    ブロックの実行時間を測る

    jump

    登録されたディレクトリへ移動(~/.saphire/jump)

    menu

    登録されたコマンドを実行(~/.saphire/menu)

サンプルスクリプト

    姓名の逆転

    cat data | each { | split | lines 1 0 | printf "%s:%s" }