サブシェルとグループの違い
- サブシェル ()
- グループ {}
サブシェルの大きな特徴は、サブシェルであるということ
サブシェルは、ほぼfork みたいなものだと思ったらいいと思います。
()
/ { }
の違い
()
はサブシェルを起動し実行する。{}
は現在のシェルで実行する。
現在のシェルの中でソースコードを実行するのか、フォークしてフォーク先でソースコードを実行するのかが一番大きな違い。この特徴があるので環境変数の保護や、作業ディレクトリの保護など変数にまつわることを隠蔽できるのが特徴になる。
目次
- サブシェルとグループの違い
- () / { } の違い
- 目次
- サブシェルとしての実験
- サブシェル時の変数
- リダイレクトについて
- グループでよくハマること:Syntax Error
- {} / () は関数の定義に使える
- まとめ { }と ( ) の違いはサブシェルを経由するかどうか
- 今回の一番の驚愕ポイント!!
- 関連記事インデックス
- 参考資料
サブシェルとしての実験
サブシェルとしての特徴を見ていく実験をしておく。
サブシェルが、プロセスを生やしていることを調べる。
コマンド
( sleep 20; )
実行中のプロセス
takuya@Desktop$ pstree 62776 -+= 62776 takuya -bash \-+= 63989 takuya -bash \--- 63990 takuya sleep 20
コレでわかるとおりです。
bash から bash が枝が生えて、枝bash からsleep が生えています。
グループの場合のプロセスツリー
グループで起動した、この場合のプロセスツリーはどうでしょうか
コマンド
{ sleep 20 ; }
実行プロセス
-+= 64457 takuya -bash \--= 64717 takuya sleep 20
グループでは、sleepを直接起動しています。これは
> sleep 20 ;
としているときと全く同じです。
サブシェル時の変数
サブシェルを使う場合、変数は受け継がれる。ただし変更は、戻されない。
これは起動時に変数を引継ぐが、起動後は別のプロセスになるので、変数への更新は反映されない。
takuya@Desktop$ a=1 ; ( echo $a; a=1234; echo $a; ) ; echo $a ; 1 # 元シェル $a 1234 # サブシェル内 $a 1 # 元シェル $a
リダイレクトについて
リダイレクトをマトメられる特徴についても見ておく。
()
サブシェルと { }
グループの 特徴として リダイレクトをマトメられる。
サブシェルはサブシェルとして一つのグループになっているので、リダイレクトはマトメられる
echo 1234 > out.txt echo 5678 > out.txt echo 9012 > out.txt
などとするときに面倒だし、() / {}
で、マトメて一括リダイレクト指定して、楽に書くことが出来る。
( )
でのリダイレクト
( echo 1234 echo 5678 echo 9012 ) > out.txt
{}
でのリダイレクト
またはグループを使うと。
{ echo 1234 echo 5678 echo 9012 } > out.txt
リダイレクトをマトメられるのでちょっと便利に使えるよね。
グループでよくハマること:Syntax Error
グループではまって面食らって「良くわからん」と使うのを断念しちゃう原因にシンタックスエラーがある。
{ }
の場合:シンタックスエラー
takuya@Desktop$ { echo 1234; } 1234 takuya@Desktop$ {echo 1234; } -bash: 予期しないトークン `}' 周辺に構文エラーがあります
開始の{
の直後に文字をつ続けてしまうと、制御構造として解釈されない
ところが、サブシェルの場合はシンタックスエラーにならない
(
は & | ;
なとと同等の優先度であるためだと思う。
( )
の場合:シンタックスOK
takuya@Desktop$ (echo 1234; ) 1234
この辺も知らないと戸惑う所。
{} / () は関数の定義に使える
理由は良くわからんが、どっちも関数定義に使える。
{}
で関数の定義
takuya@Desktop$ func_a () ( echo 1 ; ); func_a ; 1
( )
で関数の定義!?
takuya@Desktop$ func_a () { echo 1 ; }; func_a ; 1
気持ち悪さがある。ただ サブシェルが変数をサブシェル内にとどめてくれるので、とても楽にローカル変数を扱う、関数を作ることが出来る
つまり、作業ディレクトリ(wd) を覚えておく、元いた場所に戻すなど、ああいう面倒な作業が一切いらなくなる。
{ }
での場合の変数の状況
takuya@Desktop$ pwd ; func_a () { cd ~; pwd ; }; func_a; pwd ; /Users/takuya/Desktop /Users/takuya /Users/takuya
( )
での場合の変数の状況
takuya@Desktop$ pwd ; func_a () ( cd ~; pwd ; ); func_a; pwd ; /Users/takuya/Desktop /Users/takuya /Users/takuya/Desktop
サブシェルを使う点において同じになるので、少し知ってると便利かもしれない。
まとめ { }
と ( )
の違いはサブシェルを経由するかどうか
サブシェルを経由して、プロセスを生やすことを除き、殆どすべて同じであると思う。
サブシェルの特徴として次のとおりです。
サブシェルとグループに共通する特徴
- 名前をつけて関数に出来る
- リダイレクトも纏めてできる。
- 環境変数は引継がれる。
- wd (現在のディレクトリ)も同じ
- 変数定義も同じ
- 引継がれる主な変数
- set / shopt
- export 済み
- trap
- cd / pushd / popd
個人的には () は fork だと思うことにしてる。
今回の一番の驚愕ポイント!!
サブシェルを関数に出来たこと。
myFunc () ( echo aaaaa ) ; myFunc;
関連記事インデックス
bashの使い方のまとめ記事のインデックス - それマグで!
参考資料
[改訂新版] シェルスクリプト基本リファレンス ??#!/bin/shで、ここまでできる (WEB+DB PRESS plus)
- 作者: 山森丈範
- 出版社/メーカー: 技術評論社
- 発売日: 2011/04/27
- メディア: 単行本(ソフトカバー)
- 購入: 9人 クリック: 119回
- この商品を含むブログ (11件) を見る