位置パラメータ(引数の取り扱い)

概要

UNIX系OSのコマンドは引数としてオプションやパス名を指定できますが、シェルスクリプトでも同じように引数を指定できます。引数で指定した値はシェルスクリプト中では位置パラメータとして受け取ります。位置パラメータは前述した通り、0〜nの数字で表し、値を参照するときは前に$記号を付けます。

位置パラメータと関連する特殊パラメータには次のものがあります。

表6-8 特殊パラメータ一覧
変数内容
$0位置パラメータの最初のものですが引数の値ではなく、コマンド名または、シェルスクリプト名(パス名)を値として持っています。
$#引数の数を値として持っています。
$*全ての引数を空白で区切り、まとめて1つの変数とした値を持っています。
$@全ての引数を個別の値として持っています。

例題

例1:位置パラメータの値を確認します。

$ set Param1 Param2 Param3 Param4 ← 位置パラメータ1から4に値を設定
$ echo $0 ← 位置パラメータ0の値を表示
/bin/bash ← コマンド名(bash)が設定されている
$ echo $1 ← 位置パラメータ1の値を表示
Param1
$ echo $2
Param2
$ echo $3
Param3
$ echo $4
Param4
$ echo $# ← 値が設定されている位置パラメータの数を表示
4
$ echo $*
Param1 Param2 Param3 Param4 ← 全ての位置パラメータの値
$ echo $@
Param1 Param2 Param3 Param4 ← 全ての位置パラメータの値
$ set "$*" ← set "$1 $2 $3 $4"と同じ
$ echo $1
Param1 Param2 Param3 Param4 ← 位置パラメータ1に全ての位置パラメータの値が設定されている
$ set Param1 Param2 Param3 Param4
$ set "$@" ← set "$1" "$2" "$3" "$4"と同じ
$ echo $1
Param1 ←  位置パラメータ1には"$1"の値が設定されている
$ echo $2
Param2
$

例2:引数で指定したディレクトリのバックアップを取ります。(ex20.sh)

#!/bin/bash
# 機能  :   引数で指定したディレクトリの下のバックアップを~/BACKUPに取ります
# 作成  :   メリー

cd $1                                   # 第1引数の値をカレントディレクトリに設定
tar cvf - . | gzip > ~/BACKUP/backup.tar.gz # バックアップ取得

echo -e "バックアップ完了\a"
$ ex20.sh $HOME/KANRI ← 引数を指定
./
./manpo.ksp
./kakei.ksp
バックアップ完了
$

例3:ディレクトリ(位置パラメータ1)の指定が無かったらメッセージを出力して中止します。(ex21.sh)

#!/bin/bash
# 機能  :   引数で指定したディレクトリの下のバックアップを~/BACKUPに取ります
# 作成  :   メリー

bkdir=${1:?"バックアップするディレクトリの指定がありません。中止します。"}

cd $bkdir
tar cvf - . | gzip > ~/BACKUP/backup.tar.gz     # バックアップ取得

echo -e "バックアップ完了\a"
$ ex21.sh ← ディレクトリの指定をしないで実行
バックアップするディレクトリの指定がありません。中止します。 ← エラーメッセージ
$

文字列のエスケープ

概要

シェルはユーザが入力した文字列を解釈して、さまざまなことを行っていますが、文字には特別な意味を持つ記号がいくつかあります。例えば、次のような記号が該当します。(全てではありません)

半角スペース タブ * ? [ ] > < ; | & $ { } ( ) #

これらの記号を単なる文字として扱いたい場合は特別な指定が必要です。例えば、「* Hello *」のメッセージを出力したい場合、単にecho * Hello *では期待した結果になりません。

$ echo * Hello *
ex01.sh  ex02.sh    ex03.sh   ex10.sh  ex20.sh  ex21.sh
loop.c   loop.prg   Hello     ex01.sh  ex02.sh  ex03.sh
ex10.sh  ex20.sh    ex21.sh   loop.c   loop.prg
$

単に「*」だけを指定したのでは、シェルは「*」を「任意の長さの任意の文字列」と解釈してしまいます。ここでは「*」を単なる文字として扱いたいので、その旨、シェルに伝える必要があります。このことをエスケープと呼んでおり、次のような、エスケープを表す記号があります。

"(引用符)
変数を認識します。
'(アポストロフィ)
変数を認識しません。(全ての文字を単なる文字として取り扱います。)
\(バックスラッシュ)
後ろの1文字を文字として認識します。

先程の、echo * Hello *の場合であれば、引用符かアポストロフィで括ります。

$ echo '* Hello *' ← アポストロフィで括ってエスケープ
* Hello *
$

例題

例1:アポストロフィと引用符の相違を確認します。

$ name=メリー
$
$ echo '*** 今日は${name}さん ***' ← アポストロフィで括る
*** 今日は${name}さん ***
$
$ echo "*** 今日は${name}さん ***" ← 引用符で括る
*** 今日はメリーさん ***
$
$ echo \* Hello \* ← *をバックスラッシュでエスケープ
* Hello *
$

例2:バックアップしたディレクトリのパス名を表示します。(ex30.sh)

#!/bin/bash
# 機能  :   引数で指定したディレクトリの下のバックアップを~/BACKUPに取ります
# 作成  :   メリー

bkdir=${1:?"バックアップするディレクトリの指定がありません。中止します。"}

cd $bkdir
tar cvf - . | gzip > ~/BACKUP/backup.tar.gz         # バックアップ取得

echo "*** ${bkdir}以下のバックアップをとりました ***"     # 引用符で括ってエスケープ
$ ex30.sh ~/KANRI
/
./manpo.ksp
./kakei.ksp
*** /home/merry/KANRI以下のバックアップをとりました ***
$

例3:コマンドを実行するときにもエスケープが必要な場合があります。

$ grep #! *.sh ← 拡張子が".sh"のファイルから、「#!」を含む行を表示する
使用法: grep [オプション]‥‥ 文字列パターン [ファイル]‥‥ ← grepの構文エラー
詳しくは`grep --help'を実行してください。
$
$ grep '#!' *.sh  ← アポストロフィで括ってエスケープ
ex01.sh:#!/bin/bash
ex02.sh:#!/bin/bash
ex03.sh:#!/bin/bash
ex10.sh:#!/bin/bash
ex20.sh:#!/bin/bash
ex21.sh:#!/bin/bash
ex30.sh:#!/bin/bash
$
$ cd DOC
$ ls
My Documents  Program Files
$
$ cd My Documents  ← My Documentsは半角スペースを含む
bash: cd: My: そのようなファイルやディレクトリはありません
$ cd 'My Documents'  ← 半角スペースをエスケープするためにアポストロフィで括る
$ ls
work.ods            財産目録.ods  総勘定元帳.ods
合計残高資産表.ods  精算表.ods    貸借対照表.ods
$