5. コマンドの接続¶
5.1. パイプライン¶
パイプの記号は >>=
です。
|
と比較すると打つのが面倒ですが、
一方でスクリプトの中で目立つので、
よく見落とされる |
よりは分かりやすいだろうという意図です。
また、厳密な裏付けはありませんが、Haskellの >>=
と
パイプの挙動は似ているので、この記号を使用しています。
パイプは次のように使います。
/usr/bin/seq '1' '5' >>= /usr/bin/tac
#Macの場合: /usr/bin/seq '1' '5' >>= /usr/bin/tail '-r'
出力は、bashで seq 1 5 | tac
したときと同じです。
上のスクリプトを pipeline.glue
というファイルに保存して実行すると次のような出力が得られます。
$ glue pipeline.glue
5
4
3
2
1
また、次のように改行することもできます。
/usr/bin/seq '1' '5'
>>= /usr/bin/tail -r
#これでもOK
/usr/bin/seq '1' '5' >>=
/usr/bin/tail -r
5.2. AND記号¶
Bシェル系の &&
に相当する記号は >>
です。
これもHaskellに由来します。次のように使います。
/bin/echo 'a' >> /bin/echo 'b' >> /bin/echo 'c'
このコードを and.glue
というファイルに保存して実行した時の出力を示します。
a
b
c
5.3. OR記号¶
一方OR記号については !>
という表記を採用しました。
- Fig.: or.glue
1 2 3 4 | import PATH
false !> echo 'Echo is executed.'
true !> echo 'Echo is not executed.'
|
実行するとこうなります。
$ glue or.glue
Echo is executed.
ANDやORは、最後に実行されたコマンドで条件分岐します。
次の例の場合、 false
が失敗するので、 >>
の右側の echo 'if'
は実行されず、その次の echo 'else'
が実行されます。
- Fig.: or2.glue
import PATH
false >> echo 'if' !> echo 'else'
動作は次のようになります。
$ glue ./or2.glue
else
一方、次の例ではifの方が出力されて、
この時の echo
が成功するのでelseは出力されません。
- Fig.: or3.glue
import PATH
true >> echo 'if' !> echo 'else'
5.3.1. バグ¶
次のように二つ !>
をつなげた時の挙動が環境によって異なるバグが発生しており、取りきれていません。
Fig.: or_bug.glue
import PATH
false !> echo 'b' !> echo 'c'
#Travis 上
$ glue ./or_bug.glue
b
c
#Ubuntu 16.04 Server, macOS Sierra
$ glue ./or_bug.glue
b
5.4. Then記号¶
?>
はthenを表します。
then記号の左側にあるコマンドが成功すると、右側のコマンドが実行されて、
さらにそれ以後にANDやORでコマンドがつながっていても実行されません。
失敗するとスクリプトが止まります。
つまり、次のようにコマンドを並べると、if文を作ることができます。
###if A then B else if C then D else E###
A ?> B
!> C ?> D
!> E
5.4.1. メモ¶
Haskellだとこうなるのでもっとスッキリのですが、A、Cに相当する部分が長くなることがあり、シェルには向いていないかもしれません。
###if A then B else if C then D else E###
A ?> B
C ?> D
othewise ?> E
5.5. 複合コマンド(doブロック)¶
コマンドを束ねたいときはdoという命令の後にインデントして複数のコマンドを記述します。 doと、doに結びつけられたコマンド全体を「doブロック」と呼びます。 doブロックは、シェルにおける複合コマンドとほぼ等価です。
5.5.1. 単純なブロック化¶
次の例は二つのコマンドを1つに束ねる例です。
- 図: do_block.glue
import PATH
do
echo 'a'
echo 'b'
この例の場合、実行した結果は束ねないときと特に同じです。
$ glue do_block.glue
a
b
5.5.2. 他の機能との併用¶
doの前には文字列やファイルへの格納や、手続き(6章)の宣言を置くことができます。
- 図: do_block_plus.glue
import PATH
#手続きの定義・宣言
proc fn = do
echo 'c'
#ファイルへの格納
file f = do
echo 'a'
#文字列への格納
str s = do
echo 'b'
cat f >> echo s >> fn
実行結果は次のようになります。
$ glue ./do_block_plus.glue
a
b
c
また、ANDやORとの併用も可能です。 次の例はORでdoブロックを接続する例です。
図: do_if_then.glue
import PATH
do
false #これで次の!>に飛ぶ
echo 'a' #実行されない
!> do
echo 'b' #これが実行される
!> do
echo 'c' #これは実行されない
実行すると、次のようにecho ‘b’だけ実行されます。
$ glue ./do_if_then.glue
b
5.5.3. スコープ¶
doブロックの中で定義した変数はdoブロックの中でのみ有効です。 doブロックの処理は本体とは別のプロセスで動作するからです。 次の例はdoブロックの中で定義したファイル変数fを、 doブロックの外で使った例です。
- 図: do_block_scope.glue
import PATH
do
file f = echo 'a'
cat f #エラーが起きる
実行すると次のようにエラーが出ます。
$ glue ./do_block_scope.glue
Execution error at line 6, char 5
line6: cat f #エラーが起きる
^
variable f not found
process_level 0
exit_status 1
pid 3128
回避するときの一例としては、次のようにシステムのファイルを使う方法があります。
実行結果は省略します。
import PATH
do
file f = echo 'a'
mv f '/tmp/hoge'
cat '/tmp/hoge'
逆に外側で作られた文字列やファイルはdoブロックの中で使うことができます。 実行例は省略しますが、次の例はエラーが起きず、「アイウエオ」と出力されます。
import PATH
str s = 'アイウエオ'
do
echo s