Bash Basics | Basicsトップページ | トップページ

シェル

シェルはUNIXオペレーティングシステム(OS)、およびUnix系OSでOSに対して処理を指示するためのインターフェースとしての役割を持ち、ハードウェアなどのリソースを制御するカーネル(核)の周辺を取り巻く殻(シェル)のようなものであるため、「シェル」と呼ばれています。
ユーザーがOSに対してログインするとGUI環境がある場合を除いてシェルのセッション(ログインシェル)が開始されます。ログインシェルユーザーごとにカスタマイズすることが可能です。


シェルの種類

シェルには多くの派生バージョンがあり、多くはBourne Shell系とC Shell系のシェルに大別されます。
Bourne Shell系

  • Bourne Shell(sh)
  • Almquist Shell(ash)
  • Bourne Again Shell(bash)
  • Debian Almquist Shell(dash)
  • Korn Shell(ksh)
  • Public Domain Korn Shell(pdksh)
  • MirBSD Korn Shell(mksh)
  • Yet Another Shell(yash)
  • Z Shell(zsh)
C Shell系
  • C Shell(csh)
  • TENEX C Shell(tcsh)
  • Hamilton C Shell

BASH - GNU Bourne-Again SHell

bashは、標準入力やファイルから読み込んだコマンドを実行する、sh互換のコマンド言語インタプリターでKorn Shell(ksh)やC Shell(csh)の便利な機能が採り入れられています。

bashはIEEE POSIX specification(IEEE Standard 1003.1)の「Shell and Utilities」に準拠する実装を目指しており、bash はデフォルトでPOSIX準拠に設定することもできます。


定義

シェルの説明では、下記の用語は以下の定義となります。

  1. ブランク(blank)
    空白文字またはタブ文字を示します。
  2. 単語(word)
    シェルが1単位として見做す文字列の並びでトークンとも呼ばれます。
  3. 名前(name)
    英数字とアンダースコアのみから構成され、かつ最初の文字が英字かアンダースコアである単語で識別子(identifier)とも呼ばれます。
  4. メタ文字(metacharacter)
    クォートされていない場合に単語の区切りとなる以下のいずれかの文字です。
    |&;()<>空白文字タブ文字改行文字
    本コンテンツではメタ文字を赤文字で表記します。
  5. 制御演算子(control operator)
    制御機能を持つトークンで以下のいずれかです。
    ||&&&;;;;&;;&()||&改行文字
    本コンテンツでは制御演算子を赤文字で表記します。


予約語

シェルで特別な意味を持つ単語がいくつかあり、これらを予約語と呼びます。
シェルの文法上、単純なコマンドで先頭の単語であるか、caseコマンドかforコマンドの3つ目の単語として以下の単語クォートされずに現れた場合、予約語として認識されます。
!casecoprocdodoneelifelseesacfiforfunctionifinselectthenuntilwhile{}time[[]]
本コンテンツでは予約語を赤文字で表記します。


シェルの起動(ログインシェルと対話型のシェル)

リモートからログインしてユーザーに最初に割り当てられたシェルとして起動されたシェル、および--loginオプション付きで起動されたシェルをログインシェルと言います。
OSに既にログインしているユーザーが端末を起動することで起動されるシェルは非ログインシェルとなります。
ログインシェルはlogin_shellが有効となっているため、このオプションの状態を確認することでログインシェルかどうかを確認することができます。

シェルが標準入力標準エラー出力がいずれも端末に接続されている状態でオプションではない引き数がなく、-cオプションが指定されていないシェル、または-iオプション付きで起動されたシェルを対話型のシェルと言います。
対話型のシェルはPS1が設定され、特殊パラメータ$-にiが含まれるため、この値を確認することで対話型のシェルかどうかを確認することができます。

シェルは起動時や終了時に設定ファイルを読み込み、初期化したり、後処理を実行します。下表に主なシェルの設定ファイルを示します。

  sh bash ksh csh tcsh zsh
/etc/.login       login login  
/etc/csh.cshrc       yes yes  
/etc/csh.login       login login  
~/.tcshrc         yes  
~/.cshrc       yes yes **  
~/.login       login login  
~/.logout       login login  
/etc/profile login login login     login
~/.profile login login * login     login
~/.bash_profile   login *        
~/.bash_login   login *        
~/.bash_logout   login        
~/.bashrc   interact + n/login        
/etc/zshenv           yes
/etc/zprofile           login
/etc/zshrc           interact
/etc/zlogin           login
/etc/zlogout           login
~/.zshenv           yes
~/.zprofile           login
~/.zshrc           interact
~/.zlogin           login
~/.zlogout           login

凡例
  • yes: 起動時
  • login: ログインシェルとしての起動時
  • n/login: ログインシェル以外の起動時
  • interact: 対話型シェルとしての起動時

注意事項

*: "~/.bash_profile", "~/.bash_login", "~/.profile"の順に最初に読み込み可能なファイルのみを読み込みます。"sh"として起動された場合は、"~/.profile"のみを読み込みます。

**: "~/.tcshrc"がない場合のみ読み込みます。

出典: Unixシェル (Wikipedia)

bashの設定ファイルが存在していて読み込みできない場合、bashはエラーを報告します。
についてケースごとに詳細に記述します。
  • ログインシェルの場合
    /etc/profileファイルが存在すれば、最初にこの設定ファイルを読み込んで実行します。
    その後で~/.bash_profile、~/.bash_login、~/.profileの順に設定ファイルを検索し、読み込み可能なファイルとして存在していれば最初に見つかったファイルを設定ファイルとして実行します。
    シェルの起動時に--noprofileオプションが指定されていた場合、これらすべての設定ファイルの読み込みと実行を抑止します。
    ログインシェルを終了する時、~/.bash_logoutファイルが存在していれば読み込んで実行します。
  • ログインシェルではない、対話型シェルの場合
    ~/.bashrcファイルが存在すれば、この設定ファイルを読み込んで実行します。
    シェルの起動時に--norcオプションが指定されていた場合、この設定ファイルの読み込みと実行を抑止します。
    --init-file、または--rcfileオプションを指定して~/.bashrcファイルではなく、任意の設定ファイルを実行させることもできます。
  • ログインシェルではない、非対話型シェルの場合
    BASH_ENVが設定されていれば、パラメータ展開コマンド置換算術式展開し、その値を設定ファイルとして読み込んで実行します。
    設定ファイルの検索にPATHは使用されません。
  • bashがshという名前で起動されたログインシェルの場合
    従来のshの起動動作を踏襲し、POSIX標準に従うように動作(設定ファイルの読み込みと実行後にPOSIXモードに入ります)します。
    /etc/profileファイルが存在すれば、最初にこの設定ファイルを読み込んで実行します。次に、~/.profileファイルが存在すれば、読み込んで実行します。
    シェルの起動時に--noprofileオプションが指定されていた場合、これらすべての設定ファイルの読み込みと実行を抑止します。
    対話型のシェルとして起動された場合は、さらにENVが設定されていれば、パラメータ展開コマンド置換算術式展開し、その値を設定ファイルとして読み込んで実行します。
    shという名前で起動されたシェルは--init-file、または--rcfileオプションを指定しても意味を持ちません。
  • bashがshという名前で起動されたログインシェル以外の場合
    従来のshの起動動作を踏襲し、POSIX標準に従うように動作(設定ファイルの読み込みと実行後にPOSIXモードに入ります)します。
    対話型のシェルとして起動された場合は、ENVが設定されていれば、パラメータ展開コマンド置換算術式展開し、その値を設定ファイルとして読み込んで実行します。
    非対話型のシェルとして起動された場合は設定ファイルを何も読み込みません。
    shという名前で起動されたシェルは--init-file、または--rcfileオプションを指定しても意味を持ちません。
  • --posixオプションを指定して起動された場合
    対話型のシェルとして起動された場合は、ENVが設定されていれば、パラメータ展開コマンド置換算術式展開し、その値を設定ファイルとして読み込んで実行します。
    非対話型のシェルとして起動された場合は設定ファイルを何も読み込みません。
  • bashがrshdやsshdなどから起動され、標準入力がネットワーク接続に接続されたシェルの場合
    ~/.bashrcファイルが存在すれば、この設定ファイルを読み込んで実行します。
    シェルの起動時に--norcオプションが指定されていた場合、この設定ファイルの読み込みと実行を抑止します。
    --init-file、または--rcfileオプションを指定して~/.bashrcファイルではなく、任意の設定ファイルを実行させることもできます。
  • シェルが実ユーザーグループ)IDと異る実効ユーザーグループ)IDで起動された場合
    設定ファイルは全く読み込まれません。また、実行環境も継承されず、SHELLOPTSBASHOPTSCDPATHGLOBIGNOREが設定されていても無視されます。
    --privilegedオプション、および-pオプションが指定されなかった場合、実効ユーザーIDには実ユーザーIDが設定されます。
    --privilegedオプション、または-pオプションが指定された場合、実効ユーザーIDは起動された時の実効ユーザーIDのままとなります。


シェルの文法

シェルは下記に示す単純なコマンドパイプラインリスト複合コマンドコプロセス関数定義を記述することができます。

単純なコマンド

シェルでは変数の代入を並べたあとに(変数の代入は省略可能です)ブランクで区切られた単語リダイレクションに続いて、最後に制御演算子を記述したものが単純なコマンドです。

[変数の代入1 [変数の代入2]...] 単語1 [単語2]...[リダイレクション制御演算子

シェルは単純なコマンドを以下に示す展開、代入、リダイレクションを左から右に記述された順で実行します。

  1. コマンドの前にある変数の代入とリダイレクションと判断された単語を保存します。
  2. 変数の代入とリダイレクション以外の単語展開します。
    展開後の最初の単語コマンド名、残りの単語が引き数と見做されます。
  3. 保存されたリダイレクションを実行します。
  4. 保存された変数の代入の=の右辺にある文字列に対して、チルダ展開パラメータ展開コマンド置換算術式展開クォートの削除を行います。
上記の結果、コマンド名が残らなかった場合、現在のシェル環境で変数の代入とリダイレクションが行われます。変数の代入は現在のシェルの実行環境で行われるため、後続の処理に影響を与えますがリダイレクションは現在のシェルの実行環境に影響を与えません。リダイレクションが失敗すると0ではない終了ステータスを返します。コマンド置換が行われた場合、コマンド置換の最後に実行されたコマンド終了ステータスを返します。コマンド置換が行われなかった場合、終了ステータスとして0を返します。
コマンド名が残っている場合、変数の代入はそのコマンド実行環境のみに設定され、コマンドの実行が行われます。このため、変数の代入は、現在のシェルの実行環境に影響を与えません。

例えば、以下が単純なコマンドの例です。
$ echo "Hello World"
Hello World
この例では変数の代入はなく、echoコマンドとその引き数"Hello World"と制御演算子である改行文字が入力されています。
その結果、文字列"Hello World"が出力されています。
$ LANG=C man bash
BASH(1)                     General Commands Manual                    BASH(1)

NAME
       bash - GNU Bourne-Again SHell
	   
	   SYNOPSIS
	          bash [options] [file]
			  
	   COPYRIGHT
			  Bash is Copyright (C) 1989-2011 by the Free Software Foundation, Inc.

	   DESCRIPTION
		      Bash  is  an  sh-compatible  command language interpreter that executes
		      commands read from the standard input or from a file.  Bash also incor-
		      porates useful features from the Korn and C shells (ksh and csh).
		
		      Bash  is  intended  to  be a conformant implementation of the Shell and
		      Utilities portion  of  the  IEEE  POSIX  specification  (IEEE  Standard
		      1003.1).  Bash can be configured to be POSIX-conformant by default.
		
	   OPTIONS
		      All  of  the  single-character shell options documented in the descrip-
		      tion of the set builtin command can be used as options when  the  shell
 Manual page bash(1) line 1 (press h for help or q to quit)
この例ではシェル変数LANGに値Cを代入してmanコマンドとその引き数bashと制御演算子である改行文字が入力されています。
その結果、デフォルトのロケールである英語でbashのマニュアルページが出力されています。
LANGの値はmanコマンド実行環境のみに設定されるため、manコマンドを実行したシェルの実行環境ではLANGに値に変化はありません。

変数の代入を並べたあとにコマンドを記述する書き方は注意が必要です。
$ x='Hello' y='world!' echo $x $y

上記の例では変数xに代入されたHelloと変数yに代入されたworld!がechoコマンドで出力されることを期待していると思いますが期待通りに出力されていません。
何故でしょうか?

実際にはこの例では、変数xとyの代入は行われていますが、echoコマンドの引き数として変数xとyは渡されているのではありません。
シェルは引き数をコマンドに渡す前に展開します。つまり、展開を行うシェルの実行環境では変数xとyは存在しておらず、空文字列として展開されます。
このため、echoコマンドを実行する際には空文字列、つまり引き数がないものとして処理されるため、正しく動作しません。
これをわかりやすくするために事前に変数xとyに別の値を代入してみましょう。
$ x=abc
$ y=xyz
$ x='Hello' y='world!' echo $x $y
abc xyz
それでは、最初の例を期待通りに実行させるためにはどのようにすれば良いでしょうか?
下記に正しい例を示します。
$ x='Hello' y='world!' bash -c 'echo $x $y'
Hello world!
この記述方法では変数xとyに値を代入したのち、bashコマンドを実行しますが、その引き数はシングルクォーテーションで囲まれているため文字列'echo $x $y'となります。
bashは-cオプションで指定された文字列'echo $x $y'をコマンドとして実行するため、echoコマンドが変数xとyを参照して処理することができます。

シングルクォーテーションではなく、ダブルクォーテーションで引き数を指定した場合はどうでしょうか?
$ x='Hello' y='world!' bash -c "echo $x $y"

この例も期待通りに動作していません。
これはシェルがダブルクォーテーションで囲まれた文字列も展開するからです。
このようにクォートの指定と展開には注意してください。

パイプライン

コマンドを実際に使用する場合、あるコマンドの実行結果(である標準出力)を別のコマンドでさらに処理したいということがよくあります。
例えば、あるファイルからデータを抽出して、それを整形したものをさらにソートするということが考えられます。
シェルの機能であるパイプラインを利用することでこれが可能となります。最も簡単なパイプラインは連結したいコマンドを | で並べて記述するだけです。
パイプラインを使うと記述した順に左側のコマンド標準出力をその右側のコマンド標準入力としてデータを引き継ぐ(連結する)ことができます。
パイプラインの連結は各コマンドリダイレクションよりも先に実行されるため、各コマンド標準入出力リダイレクションがある場合、それぞれの指定で上書き(優先)されます。
|& による標準エラー出力の連結は各コマンドリダイレクションよりも後に実行されるため、各コマンド標準エラー出力リダイレクションがある場合、その指定を上書きします。

[time [-p]] [!コマンド1 [[|コマンド2 ...]
または
[time [-p]] [!コマンド1 [[|&コマンド2 ...]

パイプラインは何段も連結することができるので、コマンド1 | コマンド2 | コマンド3 | コマンド4のように実行することも可能です。
| ではなく、|& でパイプラインを繋ぐと前段のコマンド標準エラー出力もパイプを通して後段のコマンド標準入力に連結することができます。
これは下記の短縮形です。
コマンド1 2>&| コマンド2
つまり、上記パイプラインは下記と等価です。
コマンド1 |& コマンド2

例えば、あるディレクトリの一覧をlsコマンドで取得し、その一覧をwcコマンドに連結することでディレクトリに存在するファイル数をカウントすることが可能です。

$ ls | wc -l
12
上記の結果では合計で12のファイル(ディレクトリを含む)が存在しています。
次の例ではシステムのネットワーク設定情報からIPv4アドレスのみを抽出し、そのIPアドレスをソートして表示しています。
$ ifconfig | grep -w inet | awk -F" " '{print $2}' | sort
127.0.0.1
192.168.1.10
192.168.10.10
パイプラインでコマンドを連結した場合の終了ステータスは以下の通りとなります。
実行例:
$ echo "Hello World" | tr a-z A-Z; echo $?
HELLO WORLD
0
echoコマンドで"Hello World"を出力し、パイプラインでtrコマンドに連結して英大文字に変換しています。
最後段のtrコマンド終了ステータスである0が返されます。
$ ! echo "Hello World" | tr a-z A-Z; echo $?
HELLO WORLD
1
echoコマンドで"Hello World"を出力し、パイプラインでtrコマンドに連結して英大文字に変換しています。
最後段のtrコマンド終了ステータスである0を論理否定した1が返されます。
$ ech "Hello World" |& tr a-z A-Z; echo $?
BASH: ECH: コマンドが見つかりませんでした...
0
コマンドのスペルが間違っているため、前段のコマンドは失敗しています。
パイプラインで標準エラーのメッセージも連結しているため、エラーメッセージがtrコマンドで英大文字に変換されています。
最後段のtrコマンド終了ステータスである0が返されます。
$ ! ech "Hello World" |& tr a-z A-Z; echo $?
BASH: ECH: コマンドが見つかりませんでした...
1
コマンドのスペルが間違っているため、前段のコマンドは失敗しています。
パイプラインで標準エラーのメッセージも連結しているため、エラーメッセージがtrコマンドで英大文字に変換されています。
最後段のtrコマンド終了ステータスである0を論理否定した1が返されます。
$ true | true | false | true; echo $?
0
最後段のtrueコマンドの終了ステータスである0が返されます。
$ ! true | true | false | true; echo $?
1
最後段のtrueコマンドの終了ステータスである0を論理否定した1が返されます。
$ shopt -so pipefail
$ true | true | false | true; echo $?
1
$ ! true | true | false | true; echo $?
0
pipefailオプションが有効化されている場合、最も後段の0以外の終了ステータスを返すfalseコマンドの終了ステータスである1が返されます。
!をパイプラインの前に指定した場合はその値を論理否定した0が返されます。
パイプラインでコマンドを連結した場合、途中でエラーが発生しても記述したコマンド全てが処理されるため、エラーが発生した場合の出力や終了ステータスの扱いにご注意ください。

パイプラインの前に予約語timeがある場合、組み込みコマンドtimeとして解釈されて記述されたコマンドの実行にかかった経過時間、ユーザー時間、システム時間がパイプラインの終了時に出力されます。
-pオプションを指定すると、timeの出力形式がPOSIX仕様となります。
TIMEFORMATに時間情報の出力書式を設定することができます。
シェルがPOSIXモードの時、後続のトークンが - で始まる場合、time予約語として認識されなくなり、エイリアスや外部コマンドを検索して実行します。また、timeの直後が改行文字の場合、シェルと子プロセスがそれまでに消費したユーザー時間とシステム時間を出力します。

注意事項:
パイプライン中の各コマンドはそれぞれ別々のプロセスとしてサブシェル内で実行されます。
.、およびsource{}によるグループコマンドもサブシェル内で実行されることに注意してください。

実行例:
$ echo "Hello World" > file | cat
echoコマンドで"Hello World"をfileにリダイレクションして、パイプラインでcatコマンドに接続しています。
パイプラインよりもリダイレクションが後に行われるため、何も出力されません。
$ cmdcmd 2>file |& cat
bash: cmdcmd: コマンドが見つかりませんでした...
存在しないコマンドcmdcmdを実行しようとしてエラーが発生しています。それを |& でパイプラインを使ってcatコマンド標準入力に接続しています。
標準エラー出力リダイレクションよりもパイプラインの接続が後で行われるため、エラーメッセージがcatコマンド標準入力と接続され、出力されます。
$ set +o posix
$ time

real    0m0.000s
user    0m0.000s
sys     0m0.000s
シェルのPOSIXモードを解除してtimeの直後に改行文字を入力すると、何も実行せずに時間情報を出力するため、全て0秒と表示されます。
$ set -o posix
$ time
user    0m0.08s
sys     0m0.07s
シェルがPOSIXモードの時、timeの直後に改行文字を入力すると、シェルと子プロセスがそれまでに消費したユーザー時間とシステム時間が表示されます。
#!/usr/bin/bash

echo "timeコマンド"
カレントディ レクトリに左記のようなスクリプトtimeを作成します。
$ PATH=.:$PATH
$ set +o posix
$ time -p sleep 1
real 1.00
user 0.00
sys 0.00
$ set -o posix
$ time -p sleep 1
timeコマンド
PATHの先頭にカレントディレクトリを追加します。
シェルのPOSIXモードを解除してtimeの直後に-pを付加して、sleepコマンドを実行すると、外部コマンドのsleepを実行し、実行にかかった時間情報を出力します。
この時、timeは-pオプションが指定されたと認識し、出力形式はPOSIX仕様となります。
シェルがPOSIXモードの時、timeの直後に-pを付加して、sleep 1を入力すると、time予約語として認識されないため、外部コマンドとして解釈され、PATHからコマンドを検索し、カレントディレクトリのtimeが実行されます。

リスト

1つ以上のパイプラインを以下のいずれかの制御演算子で区切って並べたものをリストと呼びます。
パイプラインの最後に;&改行文字を記述することもできます。

制御演算子説明
&&の前に記述されたパイプラインをサブシェル内でバックグラウンドで実行します。この(&の前に記述された)パイプライン終了ステータスは常に0となります。
&の次にパイプラインの記述があれば、前のパイプラインの終了を待たずに&の次に記述されたパイプラインを実行します。
;;の前に記述されたパイプラインをフォアグランドのサブシェル内で実行し、そのパイプラインの終了を待ってから;の次に記述されたパイプラインを順番に実行します。
改行文字改行文字の前に記述されたリストまたは、パイプラインをフォアグラウンドのサブシェル内で実行します。
&&&&の前に記述されたパイプラインをフォアグラウンドのサブシェル内で実行し、そのパイプライン終了ステータス0を返した場合に限って、&&の次に記述されたパイプラインを実行します。
||||の前に記述されたパイプラインをフォアグラウンドのサブシェル内で実行し、そのパイプラインが0以外の終了ステータスを返した場合に限って、||の次に記述されたパイプラインを実行します。
&で終了するコマンド行を除いて終了ステータスは最後に実行されたパイプライン終了ステータスとなります。
リストで記述する制御演算子のうち、&&||は同じ優先順位を持ち、続いて、;&が同じ優先順位となります。

実行例:
$ echo Hello; echo World; echo '!!'
Hello
World
!!
echoコマンドを全て;で区切って記述しているため、順番に実行されます。
$ echo Hello & echo World & echo '!!'
[1] 23336
[2] 23337
!!
Hello
World
[1]-  終了                  echo Hello
[2]+  終了                  echo World
echoコマンドを全て&で区切って記述しているため、それぞれバックグラウンドで実行され、処理が終了したものから出力されます。このため、出力順はそのたびに不定となります。
$ true && true && echo Hello
Hello
$ echo $?
0
$ true && false && echo Hello
$ echo $?
1
$ false || false || echo Hello
Hello
$ echo $?
0
$ false || true || echo Hello
$ echo $?
0
truefalseを使って終了ステータスによる違いを示しています。
&&の場合、直前のコマンド終了ステータス0で終了した時のみ、次のコマンドが実行されていることがわかります。
一方で||の場合、直前のコマンドが0以外の終了ステータスで終了した時のみ、次のコマンドが実行されていることがわかります。

コプロセス

下記のようにコマンド予約語coprocで始まる場合、制御演算子&コマンドに付加した時と同じようにサブシェル内で非同期に実行されます。
コプロセスとして非同期に実行されたコマンドと実行したシェルの間には双方向のパイプが生成され、標準入出力を介してデータをやり取りすることができます。

coproc [コプロセス名コマンド [リダイレクション]

コプロセス名は複合コマンドの場合に指定することができます。それ以外の場合にコプロセス名を指定しようとすると、単純なコマンドの最初の単語として認識されます。コプロセス名を指定しなかった場合のデフォルトの名前はCOPROCとなります。
コプロセスとしてコマンドを実行するとシェルに指定したコプロセス名(指定しなかった場合は、COPROC)の配列変数が生成されます。
実行されたコマンド標準入力標準出力がシェルのファイルディスクリプタの1つとそれぞれパイプによって接続されます。
実行されたコマンド標準出力が接続されるファイルディスクリプタ配列変数 コプロセス名[0] に代入され、実行されたコマンド標準入力が接続されるファイルディスクリプタ配列変数 コプロセス名[1] に代入されます。
コプロセスのパイプコマンドリダイレクションよりも先に実行されるため、コマンド標準入出力リダイレクションを指定した場合、指定されたリダイレクションで上書き(優先)されます。

ファイルディスクリプタ単語展開により、シェルのコマンドの引き数やリダイレクションに指定することもできます。
コプロセスの実行で生成されたサブシェルのプロセスIDは変数 コプロセス名_PID に代入されます。
実行例はコプロセスとのパイプを参照してください。

複合コマンド

  • (リスト)
    リストはサブシェル内で実行され、シェルの環境に影響を与えるような変数の代入、組込コマンドの実行はサブシェル内で閉じて行われるため、リストの実行後に現在のシェルの環境が影響を受けることはありません。
    終了ステータスリスト終了ステータスとなります。

    実行例:
    $ STR="Hello World"; (STR='Hello World!!'; echo ${STR};); echo $STR
    Hello World!!
    Hello World
    $ set -- apple orange; (set -- grape lemon; echo $@); echo $@
    grape lemon
    apple orange
    
    • 現在のシェルで変数STRに"Hello World"を代入し、()によってサブシェル内で変数STRに'Hello World!!'を代入しています。
      サブシェル内でechoコマンドで変数STRを出力するとHello World!!が出力されますが、サブシェルの外側(現在のシェル)は影響を受けずに元の値であるHello Worldが出力されています。
    • setで現在のシェルの位置パラメータにappleとorangeを設定し、()によってサブシェル内で位置パラメータにgrapeとlemonを設定しています。
      サブシェル内でechoコマンドで位置パラメータ出力するとgrapeとlemonが出力されますが、サブシェルの外側(現在のシェル)は影響を受けずに元の値であるappleとorangeが出力されています。
    $ DATE=($(date))
    $ for ((i=0; i<${#DATE[*]}; i++)); do echo ${DATE[$i]}; done
    2022年
    3月
    13日
    日曜日
    11:44:49
    JST
    
    ()コマンド置換を組み合わせてコマンドの実行結果(標準出力)を変数に代入することができますが、この例の外側の()配列変数に値を代入するための括弧であり、複合コマンドの括弧ではありません。内側の$()の括弧はコマンド置換となります。
    この例ではdateコマンド標準出力配列変数として代入する例を示しています。

    $ (i=1;IFS=$'\n'; while read l; do printf "%06d: %s\n" $((i++)) "$l"; done;) <source.sh >source.sh.txt
    
    この例ではsource.shを1行ずつ読み込んで、各行の行頭に6桁の行番号を付加したものをsource.sh.txtとして書き込んでいます。
    IFSを変更していますが、サブシェル内での変更であり、現在のシェルは影響を受けません。
  • { リスト; }
    この記述は「グループコマンド」と呼ばれ、単にコマンドがグループ化されたものでリストは現在のシェルで実行されます。
    このため、変数の代入、組込コマンドの実行が行われた場合、現在のシェルの環境が影響を受けます。
    リストの最後は;改行文字で終わる必要があります。
    {}予約語であり、{リストの間、リスト}の間はそれぞれ空白文字メタ文字で分かれている必要があり、予約語として認識される場所に記述する必要があります。
    終了ステータスリスト終了ステータスとなります。

    実行例:
    例として下記のようなスクリプトset.shを作成して確認します。
    #!/usr/bin/bash
    
    STR="Hello Hello"
    
    $ STR="Hello World"; ( . ./set.sh ); echo ${STR}
    Hello World
    $ STR="Hello World"; { . ./set.sh; }; echo ${STR}
    Hello Hello
    $ STR="Hello World"; { ./set.sh; }; echo ${STR}
    Hello World
    $ STR="Hello World"; { . ./set.sh; } | cat; echo ${STR}
    Hello World
    $ STR="Hellow World"; { STR="Hello Hello"; }; echo ${STR}
    Hello Hello
    
    set.shでは変数STRに"Hello Hello"を代入しています。
    • ()によるコマンドの実行はサブシェル内で行われるため、.、およびsourceコマンドによる実行であっても現在のシェルは影響を受けません。このため現在のシェルで設定した"Hello World"が出力されます。
    • {}によるコマンドの実行は現在のシェル内で行われるため、.、およびsourceコマンドによるスクリプトの実行による影響を受けます。このためスクリプト内で設定した"Hello Hello"が出力されます。
    • {}によるコマンドの実行は現在のシェル内で行われますが、スクリプトの実行はサブシェル内で行われるため、現在のシェルは影響を受けません。このため現在のシェルで設定した"Hello World"が出力されます。
    • {}によるコマンドの実行は現在のシェル内で行われますが、パイプラインによるそれぞれのコマンドの実行はサブシェル内で行われるため、現在のシェルは影響を受けません。このため現在のシェルで設定した"Hello World"が出力されます。
    • {}によるコマンドの実行は現在のシェル内で行われるため、コマンドの実行による影響を受けます。このため{}内のコマンドで設定した"Hello Hello"が出力されます。
    例として下記のようなスクリプトgroup.shを作成して確認します。
    #!/usr/bin/bash
    
    {
        EXT="txt"
        STR1="Title"
        STR2="Subject"
        DIR=$(pwd)
        i=1
        
        for file in $(grep -l "${STR}" ${DIR}/*.${EXT})
        do
            echo "$((i++)): $file"
            eval sed -i -e 's/^${STR1}:/${STR2}:/' $file
        done
    } > result 2>&1
    
    echo "Count: $((--i))"
    
    group.shではカレントディレクトリにある拡張子がtxtの全てのファイルに"Title"という文字列が含まれていた場合、"Subject"に書き換え、 書き換えたファイル名をresultに書き出しています。
    • {}内の最初で使用する変数を設定しています。
      EXT: 書き換える対象ファイルの拡張子
      STR1: 書き換える対象の文字列
      STR2: 書き換える文字列
      DIR: 書き換える対象ファイルがあるディレクトリ
      i: 件数をカウントする変数
    • forのループで使用する変数をfileとしています。
      繰り返す対象としてgrep -lコマンドで書き換える文字列を含むファイル名を抽出しています。
    • 現在のカウントと対象となるファイル名を標準出力に出力しています。
    • evalコマンドを使用して続く文字列を展開した結果をコマンド(sedコマンドとその引き数)として実行しています。
    • {}全体をリダイレクションすることで全ての標準出力標準エラー出力をresultに書き出しています。
    • {}内のコマンドは現在のシェルで実行されるため、スクリプトの最後の行のechoコマンドで{}内の変数iを展開して書き換えた件数を出力しています。
  • (())
    式が算術式評価の規則に従って評価され、式の値が0以外の場合、終了ステータスは0になり、式の値が0の場合、終了ステータスは1となります。
    (())」は「let "式"」と等価です。
    ((および))予約語ではないため、式との間に空白は必要ありません。

    実行例:
    $ ((i=10,j=20,i*=j)); echo $i, $j
    200, 20
    
    カンマ演算子を使った例です。
    左から右に評価されるため、変数iへの代入、変数jへの代入、i*=jの評価が順に行われます。
    $ ((i=3,j=10,i*=++j)); echo $i, $j
    33, 11
    
    上記の例に似ていますが、3つ目のオペランドの変数jが前置インクリメントとなるため、i=i*(j+1)となります。
    $ ((i=23, j=12, i>j && (i-=j))); echo $i, $j
    11, 12
    
    論理的ANDを含む例です。
    i>jが評価され1を返す(真となる)ため、i-=jが評価されます。
    $ let (i=23, j=12), i>j && (i-=j); echo $i, $j
    11, 12
    
    上記をletで記述した例です。
    $ (((i=23, j=12), '!i>j' && (i-=j))); echo $i, $j
    23, 12
    
    算術式中に!を含む場合、クォートが必要です。
    履歴展開が有効な場合、ダブルクォートで!をクォートすることはできません。
  • [[  ]]
    記述された式を条件式として評価を行い、終了ステータスとして真(0)または偽(1)を返します。
    条件式は演算子とプライマリから構成されます。
    [[]]予約語であり、[[と式の間、式と]]の間はそれぞれ空白文字メタ文字で分かれている必要があり、予約語として認識される場所に記述する必要があります。
    [[]]の間にある単語に対してはパス名展開単語の分割は行われません。チルダ展開パラメータ展開算術式展開コマンド置換プロセス置換クォートの削除が行われます。
    条件式の演算子はクォートされてはいけません。

    実行例:
    $ touch a
    $ if [[ -f a ]]; then echo ファイルが存在します。; fi
    ファイルが存在します。
    
    touchコマンドでファイルを作成し、条件式でファイルが存在していればメッセージを出力しています。

    $ WORD="Hello World"
    $ [[ ${WORD} == Hello* ]] && echo True || echo False
    True
    
    条件式パターンマッチングを行う例です。
    特殊パターン文字を使ったパターンマッチングを行う場合、パターンはクォートせずに指定する必要があります。

    $ DATETIME=$(date "+%Y/%m/%d %H:%M:%S"); echo ${DATETIME}
    2022/03/13 18:09:35
    $ [[ ${DATETIME} =~ ^([0-9]{4})\/([0-9]{2})\/([0-9]{2})\ ([0-9]{2}):([0-9]{2}):([0-9]{2})$ ]]
    $ echo ${BASH_REMATCH[1]}-${BASH_REMATCH[2]}-${BASH_REMATCH[3]}
    2022-03-13
    $ echo ${BASH_REMATCH[4]}:${BASH_REMATCH[5]}:${BASH_REMATCH[6]}
    18:09:35
    
    拡張正規表現を使ったパターンマッチングの例となります。
    正規表現中の括弧による部分式にマッチした文字列は配列変数BASH_REMATCHに保存されます。

    $ [[ $(diff -q file1 file2>/dev/null)$? -eq 1 ]] && cp -f file1 file2
    
    $(コマンド)$?というコマンド置換終了ステータス展開される例です。
    この例では、file1とfile2に差分があった場合、file1をfile2に上書きでコピーしています。
    diffコマンド標準出力のみを/dev/nullにリダイレクションしています。diffコマンドで何らかのエラー(比較対象のファイルが存在しないなど)が発生した場合、標準エラー出力に出力されます。
  • for 変数名 [ [ in [ 単語 ... ] ] ; ] do リスト ; done
    inに続く単語リストを展開して各要素を順に変数の値に代入し、その都度リストを実行します。
    in 単語」が省略された場合、現在のシェルの位置パラメータを順に変数の値に代入し、その都度リストを実行します。
    リストが実行された場合、最後に実行されたコマンド終了ステータスが返されます。
    inに続く単語が省略されるか、展開の結果として空文字列となった場合、リストは実行されずに終了ステータスとして0を返します。

  • 実行例:
    $ for i in {0..9}; do echo $i; done
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    この例ではブレース展開を使って0から9までの数字を単語として展開されるため、10回分の繰り返し(0から9まで)となります。
    $ set -- apple orange banana grape
    $ for var in "$@"; do echo $var; done
    apple
    orange
    banana
    grape
    
    位置パラメータ単語としてパラメータ展開されるため、位置パラメータの数だけ繰り返しとなります。
    下記のスクリプトmod.shを作成して確認します。
    #!/usr/bin/bash
    
    for file in `ls`
    do
        if [[ -f $file ]]; then
            mod=($(stat -c "%a" ${file}))
            if [[ $((0$mod & 0600)) -eq 0600 ]]; then
                echo ${file}: 書き込み権、読み込み権あり
            elif [[ $((0$mod & 0600)) -eq 0400 ]]; then
                echo ${file}: 書き込み権あり
            elif [[ $((0$mod & 0600)) -eq 0200 ]]; then
                echo ${file}: 読み込み権あり
            else
                echo ${file}: アクセス権なし
            fi
        fi
    done
    
    コマンド置換によってコマンド標準出力単語として展開されます。
    この例ではlsコマンド標準出力カレントディレクトリのファイル名が展開されます。
    それぞれのファイルに対して所有者の権限を確認しています。
  • for (( 式1 ; 式2 ; 式3 )) ; do リスト ; done
    最初に式1が算術式評価の規則に従って評価されます。
    次に式2を算術式評価の規則に従って評価し、評価結果が0でなければ、リストを実行して式3を算術式評価の規則に従って評価します。
    式2が0を返すまで式2の評価、リストの実行、式3の評価を繰り返します。
    式が省略された場合、1が返されたものとして扱われます。
    リストが実行された場合、最後に実行されたコマンド終了ステータスが返され、リストが一度も実行されなかった場合(最初の式2の評価で0が返された場合)、0が返されます。
    式のいずれかが誤っている場合、終了ステータスとして1が返されます。

    実行例:
    $ for ((i=0; i<=9; i++)); do echo $i; done
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    この例では0から9まで繰り返す例です。
    式1に初期値、式2に終了条件を柔軟に設定できるため、繰り返す範囲を簡単に指定することができます。

    $ set -- apple orange banana grape
    $ for ((i=1; i<=$#; i++)); do eval echo '\$'$i: \$$(($i)); done
    $1: apple
    $2: orange
    $3: banana
    $4: grape
    
    位置パラメータの数だけ繰り返す例です。

    $ for ((end=$(date --date "+1 mins" +%s); $(date +%s)<$end;)) ; do date; sleep 10; done
    2022年  3月 13日 日曜日 19:01:01 JST
    2022年  3月 13日 日曜日 19:01:11 JST
    2022年  3月 13日 日曜日 19:01:21 JST
    2022年  3月 13日 日曜日 19:01:31 JST
    2022年  3月 13日 日曜日 19:01:41 JST
    2022年  3月 13日 日曜日 19:01:51 JST
    
    現在の時間から一定時間後まで処理を繰り返す例です。
    この例では現在の時間から1分後まで10秒ごとに時間を出力しています。
  • select 変数名 [ in 単語 ... ] ; do リスト ; done
    inに続く単語リストを展開して各要素を順に番号を付加して標準エラー出力に出力します。
    in 単語」が省略された場合、現在のシェルの位置パラメータを順に番号を付加して 標準エラー出力に出力します。
    続いてPS3をプロンプトとして標準エラー出力に出力し、標準入力から1行読み込みを行います。
    読み込んだ行が出力した単語のいずれかに対応する番号であれば変数にその単語が代入され、対応する番号以外が入力された場合、空文字列が代入されます。
    読み込んだ行が空であればPS3のプロンプトを再び出力し、標準入力から1行読み込みを行います。
    読み込んだ行はREPLYに代入されます。
    breakコマンドが実行されるまで行が読み込まれるたびにリストを実行し、再びPS3のプロンプトを出力して行の読み込みを繰り返します。
    EOFを読み込むとリストは実行されず、コマンドが終了します。
    リストが実行された場合、最後に実行されたコマンド終了ステータスが返され、リストが一度も実行されなかった場合、0が返されます。

    下記のスクリプトselect.shを作成して確認します。
    #!/usr/bin/bash
    
    PS3="fruilt?: "
    select fruit in apple orange banana exit;
    do
        if [[ -n ${fruit} ]]; then
            echo "${fruit}が選択されました。";
            if [[ ${fruit} == "exit" ]] ; then
                echo "終了します。"
                exit
            elif [[ ${fruit} == "apple" ]] ; then
                price=380
            elif [[ ${fruit} == "orange" ]] ; then
                price=350
            elif [[ ${fruit} == "banana" ]] ; then
                price=300
            fi
            echo "${fruit}の価格は${price}です。"
        else
            echo "${REPLY}は正しくありません。" 1>&2
            echo "正しい値を入力してください。" 1>&2
        fi
    done
    

    実行例:
    $ ./select.sh 
    1) apple
    2) orange
    3) banana
    4) exit
    fruilt?: 1
    appleが選択されました。
    appleの価格は380です。
    fruilt?: 
    
    inに続く単語に番号が付加され、一覧として標準エラー出力に出力されます。
    続けて入力を促すプロンプトとしてPS3に設定された文字列が標準エラー出力に出力されます。
    1を入力すると対応する単語appleがselectに続けて指定された変数fruitに代入されます。
    読み込まれた行はREPLYにも代入されます。
    ifによって処理が分岐され、${fruit} == "apple"が成立するため、thenに続くprice=380が実行されます。
    echoコマンドによって選択された${fruit}とその${price}が標準出力に出力されます。
    再びPS3をプロンプトとして出力して入力を待ちます。
    $ echo 3 > data
    echo 1 >> data
    $ ./select.sh <data
    1) apple
    2) orange
    3) banana
    4) exit
    fruilt?: bananaが選択されました。
    bananaの価格は300です。
    fruilt?: appleが選択されました。
    appleの価格は380です。
    fruilt?: 
    
    最初にデータファイルdataを作成します。
    ここではechoコマンドによって3と1を1行ずつリダイレクションして書き込んでいます。
    作成したデータファイルをリダイレクションを使ってselect.shの入力としています。
    1行ずつデータが読み込まれ、それぞれ3と1に対応する単語bananaとappleが変数fruitに代入されます。
    読み込まれた行はREPLYにも代入されます。
    ifによって処理が分岐され、${fruit} == "banana"と${fruit} == "apple"が成立するため、thenに続くprice=300とprice=380がそれぞれ実行されます。
    echoコマンドによって選択された${fruit}とその${price}が標準出力に出力されます。
    データファイルの読み込みが終端まで到達したためEOFとなり、selectコマンドは終了します。
    $ ./select.sh 
    1) apple
    2) orange
    3) banana
    4) exit
    fruilt?: Ctrl+D
    $
    
    PS3をプロンプトの出力後、Ctrl+Dを入力するとEOFと見做され、selectコマンドは終了します。
    $ ./select.sh 
    1) apple
    2) orange
    3) banana
    4) exit
    fruilt?: 4
    exitが選択されました。
    終了します。
    
    4(exit)を入力した場合、${fruit} == "exit"が成立するため、メッセージを出力してスクリプトを終了しています。
  • case 単語 in [ [(パターン1 [ | パターン2 ] ... ) リスト ;; ] ... esac
    caseに続く単語に対してはパス名展開単語の分割は行われません。チルダ展開パラメータ展開算術式展開コマンド置換プロセス置換クォートの削除が行われます。
    展開された単語がそれぞれのパターンに対して順にパターンマッチングの規則を用いてマッチングするか評価します。
    シェルのオプションnocasematchが有効化されている場合、パターンマッチングでアルファベットの大文字と小文字の区別はされません。
    単語がパターンにマッチングすると対応するリストが実行されます。
    リストに続く;;演算子の代わりに;&または、;;&も指定でき、それぞれ以下のように制御されます。
    演算子説明
    ;;最初にマッチしたパターンに対応するリストのみが実行されます。
    ;&マッチしたパターンに対応するリストと次に続くパターンに対応するリストが実行されます。
    この時、次に続くパターンにマッチしていなくても対応するリストが実行されます。
    ;;&マッチしたパターンに対応するリストが実行され、引き続き後続のパターンの評価が続けられます。
    他にマッチしたパターンがあれば対応するリストが実行されます。

    下記のスクリプトcase.shを作成して確認します。
    #!/usr/bin/bash
    
    while :
    do
        echo "文字を入力してください"
        read var
        case ${var} in
        ( 1|2 )
    	    echo ${var}が入力されました;&
        ( [0-9] )
    	    echo 数字が入力されました;;
        ( a* )
    	    echo 'a*'が入力されました;;&
        ( abc* )
    	    echo 'abc*'が入力されました;;&
        ( abcd  )
    	    echo abcdが入力されました;;
        ( exit  )
    	    echo "終了します"; exit ;;
        esac
    done
    

    実行例:
    $ ./case.sh 
    文字を入力してください
    1
    1が入力されました
    数字が入力されました
    文字を入力してください
    
    入力された「1」は最初のパターン「1|2」にマッチするため、対応するechoが実行されます。
    演算子が「;&」であるため、次に続くパターンに対応するechoも無条件で実行され、その演算子が「;;」であるため、caseコマンドの実行は終了します。
    $ ./case.sh 
    文字を入力してください
    3
    数字が入力されました
    文字を入力してください
    
    入力された「3」はパターン「[0-9]」にマッチするため、対応するechoが実行されます。
    演算子が「;;」であるため、caseコマンドの実行は終了します。
    $ ./case.sh 
    文字を入力してください
    a
    a*が入力されました
    文字を入力してください
    
    入力された「a」はパターン「a*」にマッチするため、対応するechoが実行されます。
    演算子が「;;&」であるため、他のパターンの評価が継続されますが、他にマッチするパターンがないため、caseコマンドの実行は終了します。
    $ ./case.sh 
    文字を入力してください
    abcd
    a*が入力されました
    abc*が入力されました
    abcdが入力されました
    文字を入力してください
    
    入力された「abcd」はパターン「a*」にマッチするため、対応するechoが実行されます。
    演算子が「;;&」であるため、他のパターンの評価が継続され、パターン「abc*」にマッチするため、対応するechoが実行されます。
    その演算子も「;;&」であるため、他のパターンの評価が継続され、パターン「abcd」にもマッチするため、対応するechoが実行されます。
    この演算子は「;;」であるため、caseコマンドの実行は終了します。
    $ ./case.sh 
    文字を入力してください
    abcde
    a*が入力されました
    abc*が入力されました
    文字を入力してください
    
    入力された「abcde」はパターン「a*」にマッチするため、対応するechoが実行されます。
    演算子が「;;&」であるため、他のパターンの評価が継続され、パターン「abc*」にマッチするため、対応するechoが実行されます。
    その演算子も「;;&」であるため、他のパターンの評価が継続されますが、他にマッチするパターンがないため、caseコマンドの実行は終了します。
    $ ./case.sh 
    文字を入力してください
    exit
    終了します
    
    入力された「exit」はパターン「exit」にマッチするため、対応するechoexitが実行され、スクリプトが終了します。
  • if リスト1; then リスト2; [ elif リスト3; then リスト4; ] ... [ else リストn; ] fi
    最初にリスト1が実行されます。リスト1の終了ステータスが0であれば、リスト2が実行されます。
    リスト1の終了ステータスが0以外であれば、elifに続くリストが順番に実行され、その終了ステータスが0であれば、対応するthenに続くリストが実行され、ifコマンドが終了します。
    最初のifに続くリストelifに続くリストのいずれも終了ステータスが0以外であれば、elseに続くリストが実行され、ifコマンドが終了します。
    いずれかのthenに続くリストまたは、elseに続くリストが実行された場合、終了ステータスは最後に実行されたコマンド終了ステータスとなります。
    それ以外の場合(if、およびelifに続くリストがすべて0以外の終了ステータスを返した場合)、終了ステータスは0となります。

    実行例はselectの例を参照してください。
  • while リスト1; do リスト2; done
    until リスト1; do リスト2; done
    whileリスト1が終了ステータスとして0を返す間、繰り返してリスト2を実行します。
    untilリスト1が終了ステータスとして0以外を返す間、繰り返してリスト2を実行します。
    リスト2が実行された場合、最後に実行されたコマンド終了ステータスが返され、リスト2が一度も実行されなかった場合、0が返されます。

    実行例:
    $ i=0; while : ; do if [[ $i -gt 9 ]]; then break; fi; echo $((i++)); done
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    はじめに変数iの値に0を代入しています。
    :コマンドは常に0を返すため、whilebreakが実行されるまで無限にdodoneに囲まれたリストを実行します。
    リストではif変数iの値を評価し、9より大きければbreakを実行してwhileコマンドを終了させています。
    変数iの値が9以下であれば、echoコマンドで変数iの値を標準出力に出力して変数iの値をインクリメントしています。

    $ i=0; while [[ $i -le 9 ]] ; do echo $((i++)); done
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    はじめに変数iの値に0を代入しています。
    whileの条件として[[条件式]]を記述し、変数iの値が9以下であれば、dodoneに囲まれたリストを実行します。
    リストではechoコマンドで変数iの値を標準出力に出力して変数iの値をインクリメントしています。

    $ i=0; until [[ $i -gt 9 ]] ; do echo $((i++)); done
    0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    上記whileの例をuntilに置き換えた例です。
    はじめに変数iの値に0を代入しています。
    untilの条件として[[条件式]]を記述し、変数iの値が9より大きくなるまで、dodoneに囲まれたリストを実行します。
    リストではechoコマンドで変数iの値を標準出力に出力して変数iの値をインクリメントしています。

関数定義

シェルは複合コマンドを関数として定義することができます。関数は一連のコマンドを名前を付けて保存したものと言えます。

関数名 () 複合コマンド [リダイレクション]
または
function 関数名 [()複合コマンド [リダイレクション]

関数は上記のいずれかの記述で定義することができます。予約語functionが記述された場合、関数名の後の()は省略することができます。
一般的に関数は{}に囲まれたリストを記述しますが、複合コマンドであればどの記述も可能です。
関数の定義でリダイレクションが指定された場合、関数が実行されるたびにリダイレクションが行われます。
関数の定義の終了ステータスは同じ名前の関数が読み込み専用で定義されているか文法エラーがある場合、0以外となりますが、正常に関数が定義できた場合は0を返します。
関数を実行した時の終了ステータスは、関数内で最後に実行されたコマンド終了ステータスとなります。
関数内でreturnに引き数を指定して任意の終了ステータスを呼び出し元に返すことができます。

exportに-fオプションを指定して実行すると、関数を実行環境エクスポートすることができます。エクスポートされた関数は後続のサブシェル内でも実行することができます。
unsetに-fオプションを指定して実行すると、関数定義を削除することができます。
declareに-fオプションを指定して実行すると、関数の名前と定義を標準出力に出力します。-Fオプションを指定して実行すると、関数名だけが標準出力に出力されます。extdebugが有効化されていれば、-Fオプションと関数名を指定して実行するとその関数が定義されているソースファイルの名前と行番号が標準出力に出力されます。

定義された関数は単純なコマンドとして現在のシェルで実行することができ、サブシェルは生成されません。
また、実行時に指定された引き数を関数内では新しい位置パラメータとして参照することができます。指定された引き数の数に合わせて特殊パラメータ$#も更新されます。$0は更新されませんが、FUNCNAMEの最初の要素(${FUNCNAME[0]})に実行中の関数名が設定されます。
DEBUGとRETURNのトラップは関数にtrace属性が与えられている場合とfunctraceが有効化されている場合を除いて継承されません。
ERRのトラップはerrtraceが有効化されている場合を除いて継承されません。
関数内でreturnを実行すると、その関数の実行は終了し、RETURNのトラップに設定されたコマンドが実行されます。その後、関数の呼び出し元に戻って次のコマンドから実行が再開されます。
呼び出し元に戻る時に位置パラメータ特殊パラメータ$#は関数を呼び出した時の状態に復元されます。
local変数を宣言することで、関数内(とその関数から呼ばれる別の関数を含む)でローカルな変数を定義することができます。
関数は自身を再帰的に呼び出すことができます。デフォルトでは再帰的な呼び出しの深さに制限はありません。
FUNCNEST変数に0より大きな値を設定すると、その値を超えた深さの関数の呼び出し(再帰呼び出し以外の別の関数の呼び出しも含む)は失敗します。
上記以外は、関数内の実行環境は、呼び出したシェルの実行環境と同じとなります。


エイリアス

シェルはエイリアスとして事前に登録された単語コマンドの読み込み時に単純なコマンドの先頭の単語として現れると別の文字列に置換することができます。
これをエイリアスと言い、aliasで登録、unaliasで削除することができます。

alias [-p] [エイリアス名[=置換する文字列] ...]

aliasコマンドを引き数を指定せずに実行するか、-pオプションを指定して実行すると、現在の実行環境に登録されている全てのエイリアスのリストが「alias エイリアス名=置換文字列」の形式で標準出力に出力されます。
置換文字列が指定されていない(エイリアス名だけの)引き数が指定された場合、そのエイリアス名で登録されているエイリアスが「alias エイリアス名=置換文字列」の形式で標準出力に出力され、真の値を返します。
置換文字列が指定されている引き数が指定された場合、現在の実行環境に登録します。
エイリアスの名前には、/、$、`、=、\、'、"、およびメタ文字は使用できませんが、置換される文字列には、メタ文字も含めてシェルの入力で記述できる文字は全て使用できます。

シェルはコマンドを解釈して実行する際、各コマンドの最初の単語クォートされていない場合、その単語がエイリアスとして登録されているかどうか確認し、事前にエイリアスとして登録されていれば登録されている文字列に置換されます。
置換された文字列の先頭の単語に対してもエイリアスかどうか評価が行われますが、置換された文字列の先頭の単語がそのエイリアスの名前と同じ場合には再帰的に置換されることはありません。
例えば、"ls -F"という文字列をlsという名前でエイリアス登録した場合、置換されたlsが"ls -F"として再び置換されることはありません。
エイリアスに登録されている置換文字列の最後の文字が空白文字の場合、エイリアスが展開された時、空白文字に続く次の単語に対してもエイリアスかどうかが評価されます。

エイリアスで置換される文字列に引き数を含んで置換時に評価させることはできません。
引き数を渡す必要がある場合は関数定義を使用してください。

シェルが対話型でない場合、expand_aliasesが有効化されていない限り、エイリアスの置換は行われません。
シェルが対話型の場合でもexpand_aliasesが無効化されると、エイリアスの置換は行われなくなります。

エイリアスの置換はコマンドの読み込み時に行われます。
このため、エイリアスの登録と置換を同じコマンド行内で行うことはできません。エイリアスは実行環境に登録を完了させてから置換することが可能となります。
これは、関数定義の中でエイリアスを行う場合も同様です。独立した行でエイリアスの登録が実行されない限り、エイリアスが置換されることはありません。

実行例:

$ alias ll='ls -l'
$ ll /usr
合計 300
dr-xr-xr-x.   2 root root  69632  4月 11 11:31 bin
drwxr-xr-x.   2 root root   4096  4月 11  2018 etc
drwxr-xr-x.   2 root root   4096  4月 11  2018 games
drwxr-xr-x. 114 root root  12288  2月 27 17:17 include
dr-xr-xr-x.  61 root root   4096  2月 27 17:48 lib
dr-xr-xr-x. 208 root root 159744  3月 27 00:41 lib64
drwxr-xr-x.  60 root root  12288  2月 13 15:55 libexec
drwxr-xr-x.  18 root root   4096  5月  6  2020 local
dr-xr-xr-x.   2 root root  20480  3月  5 15:17 sbin
drwxr-xr-x. 328 root root  12288  2月 27 17:48 share
drwxr-xr-x.   5 root root   4096  2月 27 17:48 src
lrwxrwxrwx.   1 root root     10 11月 23  2018 tmp -> ../var/tmp
$ alias hello='echo Hello World'
$ hello
Hello World


コメント

シェルが対話的に実行されていてシェルのオプションinteractive_commentsが有効化(デフォルトで有効化)されているか、非対話で実行(例えば、スクリプトなど)されている場合、# で始まる単語があると、その単語から行末まではコメントと見做され、全て無視されます。


引き数とオプション

bashを含むコマンドを実行する際、コマンド名に続けて指定される一連の単語を引き数と言います。
引き数のうち、-や+(または--)で始まる単語コマンドの振舞いや属性を指定するものをオプションと言い、単一の単語で構成されるものとオプションに続く単語と合わせて構成されるものがあります。


オプション

シェルの起動時に下記の属性を設定したり、setshoptで実行中のシェルの属性を変更することができます。
bashsetはオプションの前に[-+]がある場合、-を付加するとそのオプションが有効となり、+を付加するとそのオプションが無効となります。

設定方法:

  • bash [オプション ...] [引き数 ...]
    オプション--(または-)以降の文字列は引き数と見做されます。
    -cまたは、-sのいずれも指定されていない場合、最初の引き数はファイル名と見做され、スクリプトファイルとして読み込まれ記述されているコマンドを実行します。bashがスクリプトを実行している時、$0にはそのスクリプトのファイル名が設定されます。
    残りの引き数はスクリプトへの位置パラメータとして設定されます。
    スクリプトの終了ステータスはスクリプト中の最後に実行されたコマンド終了ステータスとなります。 コマンドが全く実行されない場合の終了ステータスは0となります。
    スクリプトファイルはカレントディレクトリから検索し、見つからなければPATHディレクトリを順に検索します。 オプションを含む引き数が何も指定されていない場合、新しいbashのセッションを起動します。
  • set [--abefhkmnptuvxBCEHPT] [-o オプション名] [引き数 ...]
    set [+abefhkmnptuvxBCEHPT] [+o オプション名] [引き数 ...]
    オプションを含む引き数が何も指定されていない場合、全てのシェル変数の名前と値、および関数を再設定できるコマンドがされます。読み込み専用の変数は再設定できません。
    オプションが指定されている場合、シェルの属性を有効化または、無効化します。
    残りの引き数は現在のシェルの位置パラメータとして置換されます。
  • shopt [-pqsu] [-o] [オプション名 ...]
    -p: 指定されたシェルの属性を再設定できるコマンドが表示されます。オプション名が指定されなかった場合、現在の全てのオプションを再設定できるコマンドが表示されます。
    -s: 指定されたシェルの属性を有効化します。オプション名が指定されなかった場合、有効化されている属性の一覧が表示されます。
    -u: 指定されたシェルの属性を無効化します。オプション名が指定されなかった場合、無効化されている属性の一覧が表示されます。
    -o: 指定できるオプション名をsetの-oで指定できるものに限定します。
    -q: 通常の出力を抑制します。
    シェルの属性を有効化または、無効化を正常に実施できた場合、終了ステータスは0となります。
    シェルの属性を表示した場合、指定された全てのシェルの属性が有効化されている場合、終了ステータスは0となります。それ以外の場合、終了ステータスは0以外の値となります。
bashsetshoptオプションの動作(属性)
[-+]a または
[-+]o allexport
[-su] -o allexport新規に設定される変数、および値が変更される変数と関数が自動的にエクスポートされます。
[-+]b または
[-+]o notify
[-su] -o notifyジョブ終了ステータス、およびジョブの状態変化を次のプライマリプロンプトの出力時ではなく、即座に出力します。
[-+]e または
[-+]o errexit
[-su] -o errexit単純なコマンドパイプライン()に囲まれたリスト{}に囲まれたリストで実行される1つのコマンドが0以外の終了ステータスで終了した場合、後続の処理を中止し即座にシェルを終了します。
ただし、以下の場合はシェルは終了せずに後続の処理を継続します。
errtraceオプションが有効化されていて、かつtrapによってERRに対するトラップが設定されていれば、シェルが終了する前に実行されます。
このオプションはシェルの実行環境ごとに適用されるため、現在のシェルとサブシェルでは別々に適用されます。それぞれのシェルの実行環境ごとにオプションを適用する必要があります。
[-+]f または
[-+]o noglob
[-su] -o noglobパス名展開を無効にします。
[-+]h または
[-+]o hashall
[-su] -o hashallハッシュテーブルを有効化し、組み込みコマンド以外のコマンドをハッシュテーブルに記憶できるようにします。
これにより外部コマンドPATHから検索するのではなく、ハッシュテーブルから高速に実行できるようにすることができます。
このオプションはデフォルトで有効化されています。
ハッシュテーブルの操作はhashで行うことができます。
[-+]k または
[-+]o keyword
[-su] -o keywordコマンド名の前にある代入文だけでなく、引き数として指定された全ての代入文をそのコマンド環境変数として追加します。

以下のスクリプトkeyword.shを作成して確認します。
#!/usr/bin/sh

echo $abc $xyz
$ ./keyword.sh 

$ abc=Hello ./keyword.sh xyz=World
Hello
$ set -k
$ abc=Hello ./keyword.sh xyz=World
Hello World
このオプションを有効化する前はコマンド名の前に記述された代入文だけが環境変数として設定され、スクリプト内で参照できます。
このオプションを有効化した後では引き数として記述された代入文も環境変数として設定され、スクリプト内で参照できるようになります。
[-+]m または
[-+]o monitor
[-su] -o monitorジョブ制御を有効化し、バックグラウンドプロセスとその終了ステータスがプロセスの終了時に表示されます。
ジョブ制御をサポートしているシステムではデフォルトで有効化されます。
[-+]n または
[-+]o noexec
[-su] -o noexecコマンドを読み込んで実行をせずにスクリプトの文法チェックのみ行います。
対話型のシェルでは無視されます。
[-+]o emacs[-su] -o emacsコマンド行の編集にemacs形式のインタフェースを使用します。
対話型のシェルではデフォルトで有効化されています。ただし、noedtingオプションが有効かされている場合を除きます。
read -eでの編集インタフェースにも影響します。
[-+]o history[-su] -o historyコマンド履歴を有効化します。
対話型のシェルではデフォルトで有効されています。
[-+]o ignoreeof[-su] -o ignoreeofIGNOREEOF=10」コマンドを実行した場合と同じ効果を持ち、行頭でEOF(<Ctl>-d)が10回続けて入力されても無視します。
それ以上のEOFが行頭で入力された場合、シェルを終了します。
[-+]o pipefail[-su] -o pipefailパイプライン中のコマンドで0以外の終了ステータスを返した最も後段(右側)のコマンド終了ステータスが返されます。
パイプラインの全てのコマンドが成功の状態で終了すると0が返されます。
--posix[-su] -o posixbashの動作がPOSIX標準と異る部分をPOSIX準拠となるように変更します。
[-+]o posix
[-+]o vi[-su] -o viコマンド行の編集にvi形式のインタフェースを使用します。
read -eでの編集インタフェースにも影響します。
-o -oに続けてオプション名を指定しなかった場合、現在有効化されているオプションが出力されます。
+o -oに続けてオプション名を指定しなかった場合、現在のオプション設定を再生成するsetコマンドが出力されます。
[-+]p または
[-+]o privileged
[-su] -o privileged特権モードを有効化します。
bash起動時にこのオプションが指定された場合、ENVBASH_ENVSHELLOPTSBASHOPTSは無視され、シェル関数も継承されません。
また、このオプションが有効化されている場合、CDPATHGLOBIGNORE環境変数は無視されます。
ユーザーグループ)IDと異る実効ユーザーグループ)IDでシェルが起動された時、同時にこのオプションが指定されている場合、シェルは異る実効ユーザーグループ)IDで起動されます。このオプションが指定されていない場合、実ユーザーグループ)IDで起動されます。
ユーザーグループ)IDと異る実効ユーザーグループ)IDでシェルが起動された後、このオプションを無効化すると実効ユーザーIDと実効グループIDは実ユーザーIDと実グループIDに設定されます。
[-+]t または
[-+]o onecmd
[-su] -o onecmdbashの起動時に指定された場合、コマンド行を1行だけ読み込んで実行してすぐに終了します。
setまたは、shoptから設定された場合、即座にそのシェルが終了します。
[-+]u または
[-+]o nounset
[-su] -o nounsetパラメータ展開を行う時、特殊パラメータの「$@」または、「$*」以外の未設定のパラメータ展開しようとするとエラーを発生させます。
シェルが対話型でなければ、0以外の終了ステータスでシェルが終了します。
--verbose[-su] -o verboseシェルが入力行を読み込んだ時、読み込んだコマンド行を標準エラー出力に出力します。
[-+]v または
[-+]o verbose
[-+]x または
[-+]o xtrace
[-su] -o xtrace単純なコマンドforコマンド、caseコマンド、selectコマンド、算術forコマンドをそれぞれ展開した後、PS4展開した値を表示し、その後にそのコマンド展開した引き数、単語のリストを標準エラー出力に出力します。
スクリプトの実行時に展開した値を含んだトレースを行えるためデバッグに使用できます。
[-+]B または
[-+]o braceexpand
[-su] -o braceexpandブレース展開を有効化します。
このオプションはデフォルトで有効化されています。
このオプションを無効化することでブレース展開を抑止できます。
[-+]C または
[-+]o noclobber
[-su] -o noclobberリダイレクション演算子>>&<>を使った上書きを禁止します。このオプションを有効化した場合、>|を使用する時のみ上書きができるようになります。
>>による追記は可能です。

実行例:
$ touch file
$ set -C
$ echo Hello > file
bash: file: 存在するファイルを上書きできません
$ echo Hello >| file
$ echo World >> file
$ cat file
Hello
World
[-+]E または
[-+]o errtrace
[-su] -o errtraceERRのトラップを関数コマンド置換、サブシェルで実行されるコマンドに継承します。
ERRのトラップは単純なコマンドパイプライン()に囲まれたリスト{}に囲まれたリストで実行される1つのコマンドが0以外の終了ステータスで終了した場合にtrapによってERRに設定されているコマンドを実行します。ただし、以下の場合を除きます。
実行例はトレース情報の出力と記録を参照してください。
[-+]H または
[-+]o histexpand
[-su] -o histexpand!を使った履歴置換を有効化します。
シェルが対話型の場合、このオプションはデフォルトで有効化されています。
[-+]P または
[-+]o physical
[-su] -o physicalcdpushdカレントディレクトリを変更する先がシンボリックリンクの場合、論理ディレクトリではなく、リンク先の物理ディレクトリに移動します。
このオプションが有効化されていない場合、論理ディレクトリへ移動します。

実行例:
$ pwd
/home/user1
$ ln -s /tmp tmp
$ cd tmp
$ pwd
/home/user1/tmp
$ set -P
$ cd /home/user1/tmp
$ pwd
/tmp
$ set +P
$ cd /home/user1/tmp
$ pwd
/home/user1/tmp
[-+]T または
[-+]o functrace
[-su] -o functraceDEBUGとRETURNのトラップを関数コマンド置換、サブシェルで実行されるコマンドに継承します。
DEBUGのトラップは単純なコマンドforコマンド、caseコマンド、selectコマンド、算術forコマンドの前、および関数内の最初のコマンドの実行前にtrapによってDEBUGに設定されているコマンドを実行します。
RETURNのトラップは関数の終了、.、およびsourceで読み込んだスクリプトが終了した場合にtrapによってRETURNに設定されているコマンドを実行します。
実行例はトレース情報の出力(DEBUGのトラップ)を参照してください。
--オプションの終わりを明示的に指定するために使用します。
bash起動時にこのオプションが指定された場合、これ以降の引き数は全てファイル名や引き数として処理されます。
setではこれ以降に引き数が指定されていない場合、現在のシェルの位置パラメータが取り消され、これ以降に引き数が指定されている場合、現在のシェルの位置パラメータがその内容(これ以降の引き数)に置換されます。
-オプションの終わりを明示的に指定するために使用します。
bash起動時にこのオプションが指定された場合、--と同じとなります。
setではこれ以降の引き数がある場合、現在のシェルの位置パラメータがその内容(これ以降の引き数)に置換されます。これ以降に引き数がない場合は位置パラメータの内容は変化しません。また、-xと-vオプションは無効となります。
-c 文字列文字列はbashが実行するコマンド行と$0から始まる位置パラメータして解釈されます。
bashを-cオプションを指定して実行すると以下のようにそれぞれのサブシェルが起動されます。
実行例:
$ bash -c 'echo $0,$1,$2,$3' コマンド名 1 2 3
コマンド名,1,2,3
サブシェルとしてbashが起動されそのbash位置パラメータが指定された引き数に設定されています。
$0: コマンド名
$1: 1
$2: 3
$3: 3
このため、echoを実行するとその位置パラメータを表示しています。
$ bash -c "echo $0,$1,$2,$3" コマンド名 1 2 3
この例ではダブルクォートでクォートされているため、コマンド行の処理時に$0,$1,$2,$3が展開されてしまいます。
その結果、上記例は以下を実行したことと同じになります。
$ bash -c echo /usr/bin/bash,,, コマンド名 1 2 3
ここで"/usr/bin/bash,,, コマンド名 1 2 3"がechoの結果として出力されないことに疑問を持たれるかも知れません。
これは-cオプションの最初の引き数である「echo」はコマンドとして解釈されていますが、それ以降の文字列は「echo」に対する引き数ではなく、現在のシェルからサブシェルとして起動された「bash」の位置パラメータとして展開されているためです。
下記のスクリプトtest.shを作成して同様に確認します。
#!/usr/bin/bash

echo '$_:' $_
echo '$$:' $$

for ((i=0; i<=${#}; i++))
do
    eval echo '\$'$i: '$'$i
done

実行例:
$ echo $$; bash -c ./test.sh aaa bbb ccc
6636
$_: ./test.sh
$$: 8461
$0: ./test.sh
上記「echo」の例で示した時のようにtest.shに続く文字列はそのスクリプトの引き数ではなく、サブシェルとして起動されたbash位置パラメータに設定されてしまっているため、$0もスクリプト名のままとなり、引き数もありません。
$ echo $$; bash -c ". ./test.sh" aaa bbb ccc
6636
$_: /usr/bin/bash
$$: 8574
$0: aaa
$1: bbb
$2: ccc
この例では.コマンドを使ってサブシェルとして起動したbashでスクリプトを読み込んで実行させています。
このため、スクリプト内で$0を参照するとコマンドに続けて指定された"aaa"が展開され、位置パラメータに"bbb"と"ccc"も展開されています。
$ echo $$; bash -c '. ./test.sh zzz' aaa bbb ccc
6636
$_: /usr/bin/bash
$$: 8578
$0: aaa
$1: zzz
この例ではスクリプトに引き数を直接与えているため、サブシェルであるbash$0を含む位置パラメータは指定された文字列となりますが、スクリプトに渡される引き数はzzzのみとなります。

このように-cで複数の文字列を指定した場合、$0を任意の文字列に書き換えることが可能です。
スクリプト内で$0の値によって処理を変更するなどの応用が考えられます。
-i  対話型のシェルとしてbashを動作させます。
--login または
-l
  ログインシェルとして起動されたかのようにbashを動作させます。
--restricted または
-r
  制限付きのシェルとしてbashを動作させます。
rbashという名前でシェルが起動された場合、このオプションが指定されたことと等価となります。
制限付きのシェルは以下について実行が制限(許可されない、実行されない)されます。
-s  このオプションが指定された場合、オプションとして認識できない文字列は対話型のシェルを起動する際の位置パラメータとして扱われます。
例えばbash -s test.shとした場合、test.shをスクリプトとして読み込むのではなく、対話型のシェルが起動し、位置パラメータ$1にtest.shが設定されます。
--dump-strings
または
-D
  このオプションが指定されると自動的に-nオプションも指定されたことになり、スクリプトの実行は行われず、スクリプト中のローカライズ対象の文字列($"文字列")を抽出して標準出力に出力します。

例として下記のようなスクリプトlocal.shを作成します。
#!/usr/bin/bash

IFS='\n'
printf $"LANG is '%s'.\n" "${LANG}"
printf $"Current time is %s.\n" "$(date)"

実行例:
$ bash -D locale.sh
"LANG is '%s'.\n"
"Current time is %s.\n"
ローカライズの手順についてはLC_MESSAGESを参照してください。
--dump-po-strings  --dump-stringsと同じですが、GNUのgettextのpoファイル形式の出力となります。

実行例:
$ bash --dump-po-strings locale.sh
#: locale.sh:4
msgid "LANG is '%s'.\\n"
msgstr ""
#: locale.sh:5
msgid "Current time is %s.\\n"
msgstr ""
--help  bashの起動のコマンド行についてのメッセージを標準出力に出力します。
--init-file <file>
または
--rcfile <file>
  対話型シェルの起動時にこのオプションが指定された場合、~/.bashrcの代わりにfileを設定ファイルとして実行します。
--noediting  対話型のシェルの場合、コマンド行を読み込む際にGNU readlineライブラリを使用しません。readlineライブラリは補完などの機能を提供しているため、このオプションが指定された場合、それらの機能が使えなくなります。
--noprofile  シェルの起動時にこのオプションが指定された場合、設定ファイル/etc/profile、~/.profile、~/.bash_profile、~/.bash_loginのいずれも読み込みません。
--norc  対話型のシェルの起動時にこのオプションが指定された場合、~/.bashrcを読み込みません。
shという名前でシェルが起動された場合、このオプションが指定されたことと等価となります。
--version  bashのバージョン情報を標準出力に出力します。
[-+]O autocd [-su] autocd対話型のシェルでディレクトリ名をコマンドとして入力した場合、cdの引き数にディレクトリ名が指定されたものとしてカレントディレクトリを変更します。

実行例:
$ pwd
/home/user1
$ mkdir temp
$ temp
bash: temp: コマンドが見つかりませんでした...
$ shopt -s autocd
$ temp
cd temp
$ pwd
/home/user1/temp
[-+]O cdable_vars [-su] cdable_varscdの引き数にディレクトリ名でない文字列が指定された場合、その文字列を変数名と見做して、その値のディレクトリカレントディレクトリを変更します。

実行例:
$ pwd
/home/user1
$ cd temp
$ pwd
/home/user1/temp
$ cd
$ shopt -s cdable_vars
$ D=temp
$ cd D
temp
$ pwd
/home/user1/temp
$ cd D
bash: cd: D: そのようなファイルやディレクトリはありません
$ unset D
$ cd
$ cd D
bash: cd: D: そのようなファイルやディレクトリはありません
[-+]O cdspell [-su] cdspell対話型のシェルでcdの引き数に指定されたディレクトリ名のタイプミスを自動的に訂正するよう試みます。訂正される誤りは文字の入れ替わり、文字の不足、冗長な文字の指定です。
訂正が行われた場合、訂正後のディレクトリ名が表示されカレントディレクトリを変更します。
[-+]O checkhash [-su] checkhashハッシュテーブルが有効化されている場合で、かつ実行しようとするコマンドがハッシュテーブルに見つかった場合、コマンドを実行する前に実際にそのコマンドが存在するかどうかチェックします。
コマンドが存在しない場合、PATHから検索します。
ハッシュテーブルにコマンドがフルパスで記憶されていて、存在しなかった場合、ハッシュテーブルから削除されます。
ハッシュテーブルにコマンド相対パスで記憶されていて、存在しなかった場合、ハッシュテーブルからは削除されません。
ハッシュテーブルに記憶されているパスにコマンドが存在せず、相対パスを除く他のパスで見つかった場合、ハッシュテーブルが更新されます。
[-+]O checkjobs [-su] checkjobs対話型のシェルを終了する前に停止中のジョブや実行中のジョブがないか確認します。
停止中のジョブや実行中のジョブがあればそれらのジョブの一覧を表示し、シェルの終了を待ちます。他のコマンドの実行を挟まずにもう一度続けてシェルの終了が試みられた場合、シェルを終了します。

実行例:
$ shopt -s checkjobs
$ sleep 600&
[1] 6196
$ exit
exit
動作中のジョブがあります。
[1]+  実行中               sleep 600 &
[-+]O checkwinsize [-su] checkwinsizeコマンドの実行後に毎回ウィンドウの大きさをチェックし、LINESCOLUMNSの値を更新します。
[-+]O cmdhist [-su] cmdhist複数行にわたるコマンドを同一の履歴エントリに保存できるようにします。この際、文法的な正しさを保つためにセミコロンが必要に応じて付加されます。
このオプションはデフォルトで有効化されています。
このオプションが無効化されると複数行にわたるコマンドはそれぞれの行ごとに履歴エントリに保存されます。

実行例:
$ history -c
$ shopt -s cmdhist
$ function hello () {
> echo "Hello World"
> }
$ history 
    1  shopt -s cmdhist
    2  function hello () { echo "Hello World"; }
    3  history 
$ shopt -u cmdhist
$ function hello () {
> echo "Hello World"
> }
$ history 
    1  shopt -s cmdhist
    2  function hello () { echo "Hello World"; }
    3  history 
    4  shopt -u cmdhist
    5  function hello () {
    6  echo "Hello World"
    7  }
    8  history 
[-+]O compat31 [-su] compat31bash version 3.1の動作と互換性を保つように以下の5つの動作を変更します。
  • [[で演算子「=~」の右辺がクォートされている場合、リテラル(単純な文字列)ではなく正規表現として扱います。
    bash version 3.2以降ではリテラルとして扱います。

    実行例:
    $ STR="Hello World"
    $ shopt -u compat31
    $ [[ $STR =~ "Hello*" ]] && echo "Match" || echo "Not Match"
    Not Match
    $ shopt -s compat31
    $ [[ $STR =~ "Hello*" ]] && echo "Match" || echo "Not Match"
    Match
    $ [[ $STR =~ 'Hello*' ]] && echo "Match" || echo "Not Match"
    Match
    
  • "a; b; c"のようなリストのコマンドの実行中に割り込みが発生するとリスト内の次のコマンドを実行します。
    bash version 4.0以降ではリスト全体の実行を中止します。

    実行例:
    $ shopt -u compat31
    $ sleep 100; sleep 100; echo Done
    ^C
    $ shopt -s compat31
    $ sleep 100; sleep 100; echo Done
    ^C
    ^C
    Done
    
    このオプションを有効化した状態でリストの実行中にCtrl+Cを入力するとリスト全体の実行が中止されずに次のコマンドを実行します。
  • [[で演算子「<」と「>」によるロケール固有の文字列比較に関して、ASCIIコードの照合順序とstrcmp(3)を使用します。
    bash version 4.1以降では現在のロケールとstrcoll(3)を使用します。
  • シェルがPOSIXモードの時、timeの直後に-で始まるオプションを付加した場合でも予約語として認識し、組み込みコマンドtimeを実行します。
    bash version 4.2のPOSIXモードでは予約語として認識しません。
  • シェルがPOSIXモードの時、ダブルクォートでクォートされたパラメータ展開にシングルクォートが含まれている場合、特殊文字として扱います。
    bash version 4.2以降のPOSIXモードでは単純な文字として扱います。

    実行例:
    $ set +o posix
    $ echo "${VAR='}"
    > ^C
    $ set -o posix
    $ echo "${VAR='}"
    '
    $ shopt -s cmpat31
    $ echo "${VAR='}"
    > ^C
    
[-+]O compat32 [-su] compat32bash version 3.2の動作と互換性を保つように以下の4つの動作を変更します。
  • "a; b; c"のようなリストのコマンドの実行中に割り込みが発生するとリスト内の次のコマンドを実行します。
    bash version 4.0以降ではリスト全体の実行を中止します。
  • [[で演算子「<」と「>」によるロケール固有の文字列比較に関して、ASCIIコードの照合順序とstrcmp(3)を使用します。
    bash version 4.1以降では現在のロケールとstrcoll(3)を使用します。
  • シェルがPOSIXモードの時、timeの直後に-で始まるオプションを付加した場合でも予約語として認識し、組み込みコマンドtimeを実行します。
    bash version 4.2のPOSIXモードでは予約語として認識しません。
  • シェルがPOSIXモードの時、ダブルクォートでクォートされたパラメータ展開にシングルクォートが含まれている場合、特殊文字として扱います。
    bash version 4.2以降のPOSIXモードでは単純な文字として扱います。
[-+]O compat40 [-su] compat40bash version 4.0の動作と互換性を保つように以下の3つの動作を変更します。
  • [[で演算子「<」と「>」によるロケール固有の文字列比較に関して、ASCIIコードの照合順序とstrcmp(3)を使用します。
    bash version 4.1以降では現在のロケールとstrcoll(3)を使用します。
  • シェルがPOSIXモードの時、timeの直後に-で始まるオプションを付加した場合でも予約語として認識し、組み込みコマンドtimeを実行します。
    bash version 4.2のPOSIXモードでは予約語として認識しません。
  • シェルがPOSIXモードの時、ダブルクォートでクォートされたパラメータ展開にシングルクォートが含まれている場合、特殊文字として扱います。
    bash version 4.2以降のPOSIXモードでは単純な文字として扱います。
[-+]O compat41 [-su] compat41bash version 4.1の動作と互換性を保つように以下の2つの動作を変更します。
  • シェルがPOSIXモードの時、timeの直後に-で始まるオプションを付加した場合でも予約語として認識し、組み込みコマンドtimeを実行します。
    bash version 4.2のPOSIXモードでは予約語として認識しません。
  • シェルがPOSIXモードの時、ダブルクォートでクォートされたパラメータ展開にシングルクォートが含まれている場合、特殊文字として扱います。
    bash version 4.2以降のPOSIXモードでは単純な文字として扱います。
  • ※RHEL/CentOS 7のbash version 4.2ではcompat41の動作が効かないようです。(設定してもversion 4.2と同じ動作となります。)
[-+]O direxpand [-su] dirspell2つのオプションを同時に有効化することで指定されたディレクトリがスペルミスなどで見つからなかった場合、補完のときに正しいパスに修正され、フルパスに置換されます。

実行例:
$ shopt -s direxpand dirspell
$ ls /ect/pass<TAB>
passwd   passwd-
$ ls /etc/passwd
[-+]O dirspell [-su] dirspell
[-+]O dotglob [-su] dotglobパス名展開に.で始まるファイル名を含めます。
GLOBIGNOREに空文字列以外が設定された場合、このオプションが有効化されます。
[-+]O execfail [-su] execfail対話型ではないシェルでexecへの引き数として指定されたコマンドの実行に失敗した場合、シェルを終了せず継続します。
このオプションが有効化されていない場合、対話型ではないシェルでexecへの引き数として指定されたコマンドの実行に失敗するとシェルは終了します。
対話型のシェルはexecへの引き数として指定されたコマンドの実行に失敗してもシェルは終了せず継続します。
[-+]O expand_aliases [-su] expand_aliasesエイリアスが有効化されます。
対話型のシェルではデフォルトで有効化されています。

実行例:
$ shopt -s expand_aliases
$ alias la='ls -la'
$ la
合計 20
drwxrwxr-x.  2 user1 user1   33  1月 18 22:36 ./
drwxrwxrwt. 20 user1 user1 4096  1月 18 22:35 ../
-rw-rw-r--.  1 user1 user1    2  1月 18 22:36 a
-r--------.  1 user1 user1    2  1月 18 22:36 b
----------.  1 user1 user1    2  1月 18 22:36 c
$ shopt -u expand_aliases
$ la
bash: la: コマンドが見つかりませんでした...
--debugger
または
[-+]O extdebug
 [-su] extdebug拡張デバッグモード(以下のデバッグのための動作)が有効化されます。
  1. declare -Fで引き数に関数名を指定した場合、その関数が定義されているソースファイルの名前と行番号が表示されます。
  2. DEBUGのトラップで実行されたコマンドが0以外を返した場合、次のコマンド(トラップを呼び出したコマンド)はスキップされ、実行されません。

    例として下記のようなスクリプトdebug.shを作成します。
    #!/usr/bin/bash
    
    function debug () {
        if [[ "${BASH_COMMAND}" == 'echo "Hello2"' ]]; then
            return 1
        fi
    }
    
    trap 'debug' DEBUG
    shopt -s extdebug
    
    echo "Hello1"
    echo "Hello2"
    echo "Hello3"
    
    実行例:
    $ ./debug.sh 
    Hello1
    Hello3
    
  3. DEBUGのトラップで実行されたコマンドが2を返し、かつシェルがサブルーチン(関数、および.、またはおよびsourceにより実行されたスクリプト)を実行している場合、次のコマンド(トラップを呼び出したコマンド)の代わりにreturnが呼び出されたものと見做されます。

    例として下記のようなスクリプトdebug.shを作成します。
    #!/usr/bin/bash
    
    function debug () {
        if [[ "${BASH_COMMAND}" == 'echo "Hello2"' ]]; then
            return 2
        fi
    }
    
    function Hello() {
        shopt -s extdebug
        trap 'debug' DEBUG
    			
        echo "Hello1"
        echo "Hello2"
        echo "Hello3"
    }
    
    Hello
    
    実行例:
    $ ./debug.sh
    Hello1
    
  4. サブルーチンが実行されるたびにBASH_ARGCに呼び出しスタックのフレームごとの引き数の数が設定され、BASH_ARGVに呼び出しスタックのフレームごとの全ての引き数が配列変数に設定されます。
  5. 関数のトレースが有効化されます。
    コマンド置換関数(リスト)で起動されたサブシェルはDEBUGとRETURNのトラップを継承します。
  6. エラーのトレースが有効化されます。
    コマンド置換関数(リスト)で起動されたサブシェルはERRのトラップを継承します。
[-+]O extglob [-su] extglobパス名展開拡張パターンマッチングが有効化されます。
[-+]O extquote [-su] extquoteパラメータがダブルクォートで囲まれている場合、${パラメータ名}の展開で$'文字列'または、$"文字列"のクォート展開します。
このオプションはデフォルトで有効化されています。

実行例:
$ str="Hello World"
$ unset var
$ shopt -s extquote
$ echo "${var:-$"str str"}"
str str
$ echo "${var:-$'hello\nworld'}"
hello
world
$ shopt -u extquote
$ echo "${var:-$"str str"}"
Hello World str
$ echo "${var:-$'hello\nworld'}"
$'hello\nworld'
[-+]O failglob [-su] failglobパス名展開でパターンにマッチするファイルが存在しない場合、エラーメッセージが表示されコマンドの実行は失敗します。
[-+]O force_fignore [-su] force_fignoreFIGNOREに設定されているファイルのサフィックスにマッチするファイルはすべて例外なく補完候補から除外されます。
このオプションが有効化されていない場合、除外されたファイルが唯一の補完候補である場合、除外されずに補完されます。
このオプションはデフォルトで有効化されています。
[-+]O globstar [-su] globstarパス名展開でパターンに**が指定された場合、サブディレクトリを再帰的に探索し、すべてのディレクトリ、サブディレクトリとファイルにマッチします。**/が指定された場合、サブディレクトリを再帰的に探索し、すべてのディレクトリとサブディレクトリにマッチします。
[-+]O gnu_errfmt [-su] gnu_errfmtシェルのエラーメッセージがGNU標準のエラーメッセージの形式で出力されます。
[-+]O histappend [-su] histappendシェルの終了時にHISTFILEで指定されているファイルにコマンドの履歴が追記されます。
このオプションが有効化されていない場合、コマンドの履歴は上書きされます。
[-+]O histreedit [-su] histreeditreadlineが使用されている場合、履歴置換に失敗するとプロンプトに続いて入力した(失敗した)コマンドが表示され、再編集が可能となります。
このオプションが有効化されていない場合、履歴置換に失敗するとプロンプトが表示されて次のコマンドの入力を待ちます。

実行例:
$ shopt -u histreedit
$ !echn
-bash: !echn: event not found
$
$ shopt -s histreedit
$ !echn
-bash: !echn: event not found
$ !echn
[-+]O histverify [-su] histverifyreadlineが使用されている場合、履歴置換の結果はいったんreadlineの編集バッファに読み込まれます。コマンドを確認したり必要な編集を行ってからシェルで実行することができます。
[-+]O hostcomplete [-su] hostcompletereadlineが使用されている場合、@を含む単語を補完しようとすると、ホスト名として補完を行います。
[-+]O huponexit [-su] huponexit対話型ログインシェルを終了するときに全てのジョブSIGHUPを送信します。
[-+]O interactive_comments [-su] interactive_comments対話型のシェルに#で始まる単語から行末までをコメントとして認識するようにします。
このオプションはデフォルトで有効化されています。
[-+]O lastpipe [-su] lastpipeジョブ制御が有効でなければ、フォアグラウンドで実行されたパイプラインの最後のコマンドを現在のシェル環境で実行します。

実行例:
$ STR="Hello World"; true | false | STR=Hello; echo $STR
Hello World
$ set +m
$ shopt -s lastpipe
$ STR="Hello World"; true | false | STR=Hello; echo $STR
Hello
$ set -m
$ STR="Hello World"; true | false | STR=Hello; echo $STR
Hello World
set +mを実行することでmonitorオプションを無効化(ジョブ制御を無効化)しています。
パイプラインの最後のSTR=Helloが現在のシェル環境で実行されるため、変数STRの値が書き換えられています。
[-+]O lithist [-su] lithistcmdhistとともに有効化された場合、複数行にわたるコマンドを同一の履歴エントリに保存する際、できる限り改行を埋め込むことで履歴を保存します。

実行例:
$ history -c
$ shopt -s cmdhist lithist
$ function hello() {
> echo "Hello World"
> }
$ history 
    1  shopt -s cmdhist lithist
    2  function hello() {
echo "Hello World"
}
    3  history 
$ shopt -u lithist
$ function hello() {
> echo "Hello World"
> }
$ history 
    1  shopt -s cmdhist lithist
    2  function hello() {
echo "Hello World"
}
    3  history 
    4  shopt -u lithist
    5  function hello() { echo "Hello World"; }
    6  history 
[-+]O login_shell [-su] login_shellシェルがログインシェルとして起動された場合、このオプションが有効化されます。
このオプションは変更することができません。
[-+]O mailwarn [-su] mailwarnbashがメールのチェックに使うファイルが前回のチェック以降にアクセスされている場合、メッセージ「The mail in メールファイル has been read"が表示されます。
[-+]O no_empty_cmd_completion [-su] no_empty_cmd_completionreadlineが使用されている場合、空行で補完を行おうとしてもPATHからコマンドを検索しません。
[-+]O nocaseglob [-su] nocaseglobパス名展開パターンマッチングで英大文字と英小文字の区別をしません。
[-+]O nocasematch [-su] nocasematchcase[[  ]]パターンマッチングで英大文字と英小文字の区別をしません。
[-+]O nullglob [-su] nullglobパス名展開パターンマッチングでパターンにマッチするファイルが存在しない場合、指定されたパターンは削除され、空文字列が展開されます。
[-+]O progcomp [-su] progcompプログラム補完機能が有効化されます。
このオプションはデフォルトで有効化されています。
[-+]O promptvars [-su] promptvarsプロンプト文字列に対して、バックスラッシュでエスケープされた特殊文字が展開された後、パラメータ展開コマンド置換算術式展開クォートの削除が行われます。
このオプションはデフォルトで有効化されています。
[-+]O restricted_shell [-su] restricted_shellシェルが制限付きのシェルとして起動された場合、このオプションが有効化されます。
このオプションは変更することができません。
[-+]O shift_verbose [-su] shift_verboseshift位置パラメータの数を超えて呼び出された場合、エラーメッセージが出力されます。
[-+]O sourcepath [-su] sourcepath.、およびsourceが引き数として与えられたファイルをPATHから検索します。
このオプションはデフォルトで有効化されています。
[-+]O xpg_echo [-su] xpg_echo組込コマンドechoがバックスラッシュによるエスケープシーケンスを展開するようにします。


コマンドの実行

コマンド単語に分割された後に単純なコマンドとその引き数(引き数は省略可能)となった場合、以下のようにコマンドが実行されます。

コマンド名に/が含まれてない場合、シェルは実行すべきコマンドの位置を特定しようとします。
コマンド名と同じ名前の関数定義が行われていれば、その関数を呼び出します。
関数定義に一致するものがなければ、組み込みコマンドのリストを検索し、一致するものがあれば、その組み込みコマンドを実行します。
関数定義組み込みコマンドも一致するものがなく、コマンド名に/が含まれない場合、bashPATHの各要素を順に検索(bashはハッシュ表を使って実行ファイルの完全なパス名を記憶します。ハッシュ表に一致するものがない場合のみ、PATHの各要素を検索します。)し、そのコマンド名に一致する実行ファイルを探します。
PATHから一致するコマンドを見つけられなかった場合、command_not_found_handleという名前の関数定義を検索し、その関数定義が存在すれば、元のコマンド名とその引き数を引き数としてcommand_not_found_handleを呼び出します。この関数終了ステータスが返されます。
この関数定義が存在しない場合、エラーメッセージを標準エラー出力に出力して、終了ステータスとして127を返します。
PATH(およびハッシュ表)からの検索に成功するか、コマンド名に/が含まれる場合には、シェルは見つかった実行ファイルを外部コマンドとして、独立した実行環境で実行します。その実行環境の引き数 0には、コマンド名が設定され、引き数が指定されていれば、引き数がコマンドに受け渡されます。
見つかったファイルが実行ファイルでもディレクトリでもない場合、シェルはスクリプトと見做してそのファイルを読み込みます。
シェルはスクリプトを実行するためにサブシェルを起動して新しい実行環境でスクリプトを実行します。

スクリプトの最初の行が#!で始まる場合、その行の残りの文字列はスクリプトを実行するインタプリタとして見做され、シェルは指定されたインタプリタをOS上で実行します。


実行環境

シェルは以下の要素からなる実行環境を持ちます。
組み込みコマンド、および関数は呼び出したそのシェルで実行されるため、独立した実行環境を持ちませんが、それ以外の単純なコマンドコマンド置換()に囲まれたリストコプロセス制御演算子&コマンドに付加した非同期コマンドパイプラインの一部として起動された組み込みコマンドはサブシェルを起動するため、独立した実行環境を持ちます。
また、いくつかの要素は親から継承することができますが、親から継承したものであっても異る実行環境ではそれぞれ独立しているためサブシェル内での変更は影響しません。


制御演算子&コマンドに付加した非同期コマンドジョブ制御が有効でなければ、デフォルトの標準入力は空ファイルである/dev/nullとなります。それ以外の場合、呼び出したシェルのファイルディスクリプタリダイレクションを含めて継承します。


ジョブ制御

シェルは実行中のプロセスを選択的に停止(サスペンド)させたり、後で実行を再開(レジューム)させたりすることができます。
bashが動作しているOSがジョブ制御をサポートしている場合、ユーザーはbashを使ってジョブの制御を行うことができます。
monitorを無効化することでジョブ制御を無効化することができます。
通常は対話型のインターフェースを通してこの機能を利用します。対話型のインターフェースはOSのカーネルの端末ドライバとbashの組み合わせで提供されます。
プロセスの動作中にサスペンド文字(通常は ^Z、Ctrl+Z)を入力すると、そのプロセスは停止させられ、bashに制御が戻ります。
遅延サスペンド文字(通常は ^Y、Ctrl+Y)を入力すると、そのプロセスが端末から読み込みを行おうとすると停止させられ、bashに制御が戻ります。
この時点でユーザーはこのジョブの状態を操作することができます。bgでバックグラウンドでの実行を継続させることができ、fgでフォアグラウンドで実行を継続させることができます。また、killでプロセスを強制終了させることもできます。
^Zの効果は即座に現れるため、未出力の出力や、先行入力した文字がある場合、破棄されます。

シェルはパイプラインごとに「ジョブ」を構成し、現在実行しているジョブの一覧を保持しています。
jobsでこの一覧をリスト表示することができます。
bashジョブを非同期(バックグラウンド)に実行した時、bashは端末に以下のような行を出力します。

[1] 26721

これは、このジョブジョブ番号が1で、このジョブを構成するパイプライン中の最後のプロセスのIDが26721であることを示しています。
1つのパイプラインに含まれる全てのプロセスは同一のジョブのメンバーです。bashは、ジョブ制御の基礎として、この「ジョブ」という抽象化機構を使用します。

ジョブの他にOSは「端末プロセスグループ」というグループの情報を管理しています。それぞれの端末プロセスグループには識別子として一意な端末プロセスグループIDというIDが割り振られています。
フォアグラウンドで実行されるプロセスは現在のシェルと同じ端末プロセスグループに所属し、バックグラウンドで実行されるプロセスは現在のシェルとは異る端末プロセスグループに所属します。
同じ端末プロセスグループに所属しているプロセスはキーボードで生成されたシグナルを等しく受信します。
このため、バックグラウンドで実行されるプロセスはキーボードで生成されたシグナルの影響を受けません。

フォアグラウンドのプロセスのみが端末から読み込むことができ、stty tostopで許可されている場合には、端末への出力を行うこともできます。
ジョブ制御が有効な状態でバックグラウンドのプロセスが端末から読み込みを行おうとすると端末ドライバからSIGTTINというシグナルが送信されます。stty tostopが有効な場合、バックグラウンドのプロセスが端末へ書き込みを行おうとするとSIGTTOUというシグナルが送信されます。このシグナルを補足しなければ、プロセスは停止します。

コマンド名を記述せずに、ジョブの名前だけを指定した場合、そのジョブをフォアグラウンドに移動させます。
つまり、fgが省略されたと見做されます。
例えば、%1はfg %1と同じで、ジョブ番号1のジョブをフォアグランドに移動します。
同様に%1 &はbg %1と同じで、ジョブ番号1のジョブをバックグラウンドで実行を再開させます。

ジョブの状態が変更されるとシェルはそれを即座に検知します。通常、bashジョブの状態変化をユーザーに報告するのは、プロンプトを出力する直前となります。
これは、実行中の他の出力を妨害しないためです。
notifyが有効化されている場合、bashジョブの状態の変化を即座に報告します。
子プロセスが終了する度に、SIGCHLDを受信します。

ジョブを停止させたままで(checkjobsオプションが有効化されている場合は実行中を含みます)bashを終了(exit)させようとすると、シェルは警告メッセージを出力します。checkjobsオプションが有効化されている場合は、ジョブとその状態を一覧表示します。この時、ジョブの状態を調べる場合には、jobsコマンドを使います。
警告メッセージの出力後、他のコマンドを実行せずにbashを再び終了させようとすると、シェルは警告を繰り返さずに、停止中のジョブを終了させます。

ジョブの指定

シェル上でジョブを指定するためには以下のような方法が使用できます。

指定説明
%nジョブ番号 nを指定します。
%%
または
%+
シェルが記憶しているカレントジョブ(フォアグラウンドで実行中に停止させられたジョブ、またはバックグランドで起動された最後のジョブ)を指定します。
%-カレントジョブの1つ前のジョブを指定します。
%文字列ジョブの名前が指定された文字列で始まるジョブを指定します。
複数のジョブ名に一致する場合、シェルはエラーを報告します。
%?文字列コマンド行中に指定された文字列を含むジョブを指定します。
複数のジョブ名に一致する場合、シェルはエラーを報告します。
jobsを実行するとカレントジョブに+のフラグ、カレントジョブの1つ前のジョブに-のフラグが付いて表示されます。

実行例:
$ sleep 100&
[1] 14666
$ sleep 200&
[2] 14674
$ sleep 300&
[3] 14681
$ sleep 400&
[4] 14688
$ jobs
[1]   実行中               sleep 100 &
[2]   実行中               sleep 200 &
[3]-  実行中               sleep 300 &
[4]+  実行中               sleep 400 &
$ fg %-
sleep 300
^Z
[3]+  停止                  sleep 300
$ jobs
[1]   実行中               sleep 100 &
[2]   実行中               sleep 200 &
[3]+  停止                  sleep 300
[4]-  実行中               sleep 400 &
$ fg %+
sleep 300
^Z
[3]+  停止                  sleep 300
$ jobs
[1]   実行中               sleep 100 &
[2]   実行中               sleep 200 &
[3]+  停止                  sleep 300
[4]-  実行中               sleep 400 &
$ fg %s
bash: fg: s: 曖昧なジョブ指定です
$ fg %sleep\ 2
sleep 200
^Z
[2]+  停止                  sleep 200
$ fg %sleep\ 100
sleep 100
^Z
[1]+  停止                  sleep 100
$ fg %?200
sleep 200
  1. sleepコマンドをそれぞれ100, 200, 300, 400の引き数と&制御演算子でバックグラウンドで起動します。
  2. jobsジョブを確認します。
    実行した順番にジョブ番号が割り振られています。
    また、最後に実行したsleep 400 &に+フラグ、その1つ前のsleep 300 &に-フラグが付いています。
  3. fg %-を実行すると-フラグの付いているジョブ番号3のsleep 300 &がフォアグラウンドで実行再開されます。
  4. キーボードからCtrl+Zを入力するとフォアグラウンドのジョブの実行がサスペンドします。
  5. jobsジョブを確認します。
    最後に実行(再開)したsleep 300 &に+フラグ、その1つ前に実行したsleep 400 &に-フラグが付いています。
  6. fg %+を実行すると+フラグの付いているジョブ番号3のsleep 300 &がフォアグラウンドで実行再開されます。
  7. キーボードからCtrl+Zを入力するとフォアグラウンドのジョブの実行がサスペンドします。
  8. jobsジョブを確認します。
    最後に実行(再開)したsleep 300 &に+フラグ、その1つ前に実行したsleep 400 &に-フラグが付いています。
  9. fg %sを実行するとsで始まるジョブが複数存在するため、エラーとなります。
  10. fg %sleep\ 2を実行するとsleep 2で始まるジョブ番号2のsleep 200 &がフォアグラウンドで実行再開されます。
  11. キーボードからCtrl+Zを入力するとフォアグラウンドのジョブの実行がサスペンドします。
  12. fg %sleep\ 100を実行するとsleep 100で始まるジョブ番号1のsleep 100 &がフォアグラウンドで実行再開されます。
  13. キーボードからCtrl+Zを入力するとフォアグラウンドのジョブの実行がサスペンドします。
  14. fg %?200を実行すると200をコマンド行に含むジョブ番号2のsleep 200 &がフォアグラウンドで実行再開されます。


シグナル

シグナルはUnix系OSにおけるプロセス間の非同期なイベント通知機構です。シグナルを送信することによって送信先の(シグナルを受け取る)プロセスに対して非同期に割り込むことができます。
シグナルを受信する側のプロセスはシグナルのハンドラを登録することによって、特定のシグナルを受信した時に任意の処理を実行することができます。
シグナルのハンドルが登録されていない場合、デフォルトの動作が実行されます。
以下のようなデフォルトの動作があります。

  • Term: プロセスの終了。
    終了ステータスとして受信したシグナル番号 + 128の値を返し、シグナルを受信して終了したことを示します。
  • Ignore: シグナルの無視。
  • Core: プロセスの終了とコアダンプの出力。
  • Stop: プロセスの一時停止(実行を中断)。
  • Continue: 停止中のプロセスの再開、停止していないプロセスでは無視。

Linuxでは以下の標準シグナル(POSIX信頼シグナル)に対応していますが、シグナルの番号(値)はアーキテクチャーに依存しているため、下表のシグナル番号はx86アーキテクチャーにおける値を示しています。
POSIX.1-1990に定義されているシグナルを以下の表に示します。
シグナル名番号(値)デフォルトの動作説明
SIGHUP1Termハングアップ端末の回線切断、クローズ時に送信。
SIGINT2Term割り込みキーボードからの割り込み、通常はCtrl+Cの入力で送信。
SIGQUIT3Core終了とコアダンプキーボードからの中止、通常はCtrl+\の入力で送信。
SIGILL4Core不正な命令不正な命令(例えば命令ではないメモリ領域へのジャンプ、特権を持たない状態で特権が必要な命令の実行など)を実行しようとした時に送信。
SIGABRT6Coreプロセスの中断abort(3)によって送信。
SIGFPE8Core浮動小数点例外浮動小数点演算でゼロ除算やオーバーフローが発生した時に送信。
SIGKILL9Term強制終了killコマンドによる明示的な強制終了時に送信。
SIGSEGV11Coreセグメンテーション違反不正なメモリを参照した時に送信。
SIGPIPE13Termパイプの破壊読み込む相手がいないパイプへの書き込み時に送信。
SIGALRM14Termアラームalarm(2)によって設定したタイマーのタイムアウト時に送信。
SIGTERM15Term終了killコマンドのデフォルトのシグナル、killコマンドによる明示的な強制終了時に送信。
SIGUSR110Termユーザー定義シグナル1ユーザーによって定義されたシグナル。
Linuxではスレッド間の同期に使用されています。また、ddコマンドが受信すると進捗状況が表示されます。
SIGUSR212Termユーザー定義シグナル2ユーザーによって定義されたシグナル。
Linuxではスレッド間の同期に使用されています。
SIGCHLD17Ignore子プロセスの終了、停止子プロセスの状態が変化した時に送信。
SIGCONT18Continue一時停止からの再開一時停止中のプロセスの実行を再開させたい時に送信。
SIGSTOP19Stop一時停止プロセスの実行を一時停止させたい時に送信。
SIGTSTP20Stop端末からの一時停止フォアグラウンドのプロセスの実行を一時停止させたい時に送信。通常はCtrl+Zの入力で送信。
SIGTTIN21Stopバックグラウンドプロセスの読み込みバックグラウンドのプロセスが端末から読み込みを行おうとした時に送信。
SIGTTOU22Stopバックグラウンドプロセスの書き込みバックグラウンドのプロセスが端末へ書き込みを行おうとした時に送信。

Single UNIX Specification Version 2(SUSv2)とPOSIX.1-2001に定義されているシグナルを以下の表に示します。
シグナル名番号(値)デフォルトの動作説明
SIGBUS7Coreバスエラー未定義のメモリ領域へのアクセス(アドレス境界を超えたアクセス、存在しない物理アドレスへのアクセスなど)時に送信。
SIGPOLL
SIGIO
29Termポーリング可能ファイルディスクリプタに対してポーリング可能(入出力が可能)な状態になった時に送信。
SIGPROF27Termプロファイリングタイマープロファイリングのタイマーのタイムアウト時に送信。
SIGSYS31Core不正なシステムコールシステムコールの引き数が不正だった時に送信。
SIGTRAP5Coreトレース/ブレークポイントによるトラップデバッグ機能によって仕掛けたトラップへの到達時に送信。
SIGURG23Ignoreソケット上の緊急データソケット上のデータに緊急を示すフラグが立っているパケットの受信時に送信。
SIGVTALRM26Term仮想アラームクロック仮想時間をカウントするタイマーによって送信。
SIGXCPU24CoreCPU時間の制限プロセスのCPU使用時間が設定値を超えた時に送信。
SIGXFSZ25Coreファイルサイズの制限ファイルサイズがファイルシステム、またはOSの制限値を超えた時に送信。

対話型のbashでトラップが全く設定されていない場合、bashSIGTERMを無視します。このため、SIGTERMのトラップが設定されていない対話型のbashkill 0で終了させることはできません。一方でSIGINTを補足し処理するため、waitでプロセスを待ち合わせている場合でも割り込みが可能です。
また、どんな場合でもSIGQUITは無視されます。
ジョブ制御が有効であれば、bashSIGTTINSIGTTOUSIGTSTPを無視します。

bashから起動した外部コマンドは、シェルが自分の親から継承した値をシグナルハンドラに設定します。
ジョブ制御が有効でなければ、非同期コマンドは継承したシグナルハンドラに加えて、SIGINTSIGQUITも無視されます。
コマンド置換の結果として実行されたコマンドは、キーボードによって生成されたジョブ制御のシグナル(SIGTTINSIGTTOUSIGTSTP)を無視します。

デフォルトでは、シェルはSIGHUPを受信すると終了します。シェルは終了する前に実行中・一時停止中の全てのジョブに対してSIGHUPを再送信します。一時停止中のジョブにはSIGCONTが送信され、そのジョブSIGHUPを受信できるようにします。
特定のジョブに対してシェルからシグナルが送信されないようにするためには、disownを使って、そのジョブジョブテーブルから削除するか、あるいはdisown -hを使って、SIGHUPを受信しないようにします。
対話型のログインシェルでhuponexitが有効化されていた場合、シェルが終了する時にSIGHUPを全てのジョブに送信します。

bashコマンドを実行中にトラップが設定されたシグナルを受信した場合、そのトラップは実行中のコマンドの完了を待って実行されます。
組み込みコマンドwaitでプロセスを待ち合わせている時にトラップが設定されたシグナルを受信した場合、待ち合わせているプロセスの状態に関係なく、即座に設定されたトラップを実行して復帰します。この時の終了ステータスは128より大きな値(受信したシグナル番号 + 128)となります。