Tech Blog

シェル関数の基本

2021-02-23

シェル関数

シェル関数の基本形

name()
{
  command
  ...
}

通常のコマンドを実行するように、nameと打てば、実行できるようになります。

シェル関数の作成

ls -lと同じ処理を行うlalという関数を作成します。

lal() {
> ls -l
> }
touch file1
lal
total 0
-rw-r--r--  1 jun  staff  0  2 23 12:55 file1

現在のシェルを終わらせるまでは、いつでもlal関数を実行可能です。

戻り値

関数ではその関数の戻り費を自分で設定できます。 returnコマンドを任意の位置に書き、そこで戻り値を設定できます。

return コマンドを明示的に書いていない場合の戻り値は、関数内の最後に実行された コマンドの実行終了ステータスになります。

動作状態による違いに関する注意

定義した関数を実行するとき、通常そのシェルの中で動作し、別のサブシェルを作りません。

ただし、関数内で標準入出力ををリダイレクトするような場合サブシェルを作って動作します。

関数がサブシェルを作って動作するかどうかによって、ちょっとした動作上の違いが起こります。

ディレクトリ

関数内でディレクトリを移動する操作を行ったとき、カレントシェルで実行している場合には、 関数の終了時にディレクトリはそれにつられて移動しています。 一方サブシェル内で実行している場合には、関数の終了後、元のディレクトリに戻ります。

変数

関数内でなにか変数に対して処理を行ったとき、カレントシェルの場合にはその変更内容が残ります。 サブシェルの場合には関数が終了すれば元の値に戻ります。

exitコマンド

関数内でexitコマンドを実行したとき、カレントシェルで実行している関数の場合には、 関数はもちろんそのシェル自体が終了します。 サブシェルで実行している場合には、その関数が終了するだけです。

引数(位置パラメタ)

lal関数に位置パラメタの指定ができるようにしてみましょう。

lal(){
> ls -l $*
> }
lal file*
-rw-r--r--  1 jun  staff  0  2 23 12:55 file1
postdisplay(){
> echo $0 $2 $3 $4
> }
postdisplay aa bb cc dd # postdisplayを引数付きで実行
postdisplay bb cc dd # $2 $3 $4が出力される。$0は関数名。

位置パラメタを使用する関数を利用する場合には、実行する前に シェルスクリプトに引数として指定されたパラメタを何らかの形で保存しておく方が良い。

#!/bin/sh
POS_PARAM="$@" # POS_PARAM変数に引数のリストを代入しておく。
some_function(){
	set ...     # setコマンドで位置パラメタを設定し直したり
	shift       # shiftコマンドでずらしたりすると、
}
some_function # 関数を利用した後では、位置パラメタもずれてしまう。
set "$POS_PARAM" # よって代入していた変数の値に戻して再利用する。

変数を使う際の注意

シェルスクリプトを1つ作ると、それで利用する変数を収めるテーブルが、1個用意されます。 その中に、シェルスクリプトで使う変数も、関数で使う変数も全て収められます。 このため、1つのシェルスクリプトで複数の関数を利用している場合など、 ある関数の中で使用する変数を使いたい場合には、他の関数で使用する変数の名前とが同じであれば それは同じ変数として処理します。 つまり関数の中でだけ利用する変数を使いたい場合には、他の関数やそれを呼んだシェルスクリプトでは決して 使わないような特殊な名前を使うようにするべきです。

関数をカレントシェルで利用すること

普通、シェルスクリプトに含まれるコマンドはそのシェルスクリプト内で動作し、 シェルスクリプトを起動したシェル上で動くわけではありません。

ところが、次のようにすれば、シェルスクリプトをカレントシェルで実行させることも可能です。

. script_file

関数も同じで、シェルスクリプト内で定義した関数は現在のシェルでは使えず、 そのシェルスクリプトの中でしか有効ではありません。 ドットコマンドを使って実行することにより、中に含まれる関数を現在のシェルが認識し利用できるようになります。

vim script
#!/bin/sh
pse()
{
	ps -ax | sort -bn
}

上記のシェルスクリプトをドットコマンドを使っカレントシェルで実行できるようになります。

. ./script
pse
......

組み込みコマンド

ヌルコマンド(:)

いつも真の結果を返すコマンドです。 実行終了ステータスで0を返します。

無限ループを作るのに利用できます。

while :
do
  if ...
  then
    break
  fi
done

また、if文の分岐内で何もしない場合の記述にも利用できます。

if comamnd-list
then
  :
else
  command
fi

thenの後には、何か1つはコマンドが必要なためです。

ヌルコマンドを利用して、空のファイルを作ることもできます。

: > filename

ドットコマンド(.)

. file

という形で使います。

新しくプロセスを作らずに現行のシェルのプロセスを使って指定されたファイルを 読み込み実行します。

その結果、指定されたファイルで記述されている変数や関数が、 現行のシェルで有効に使えるようになります。

breakコマンド

forやwhileのループから抜け出る時に使用するコマンドです。

デフォルトでは1個のループを抜けます。

cdコマンド

cd directory

で指定したディレクトリに移動します。

continueコマンド

forやwhileのループ内で、次のループ処理に移行したい場合に利用します。

echoコマンド

echo parameter

引数の部分を標準出力に表示するコマンドです。

evalコマンド

複数の変換処理を1度にやってしまいたい時に利用します。

VAR1=value
VAR2=VAR1
eval echo $"$VAR2"
value

evalコマンドは、変数の置き換えやコマンドの変換、ワイルドカードの展開などが複雑に 絡んでいる時に1行のコマンドでいっぺんに展開させてしまうものです。

また、evalコマンドはあるコマンドの結果が「何かを実行させるコマンドの形式をとって」返されたとき、 それをそのまま実行させるというような場合にも使用します。

eval `echo $"$VAR2"`
zsh: command not found: value

展開した結果のvalueという文字列をそのままコマンドとして実行させようとしています。

execコマンド

exec command

execコマンドは、新しくプロセスを作らず現行のカレントシェルのプロセスと置き換えて、 引数のコマンドを実行させます。 このコマンドを実行したら、もう元のシェルに戻ることはありません。

#!/bin/sh
exec ls -l
echo abc
./exec
total 16
-rwxr-xr-x  1 jun  staff  30  2 25 06:28 exec
-rw-r--r--  1 jun  staff   0  2 24 18:17 hello
-rw-r--r--  1 jun  staff   6  2 24 18:15 hello.txt
-rw-r--r--  1 jun  staff   0  2 24 18:17 hello2

exitコマンド

exitコマンドはシェルを終了するときに使います。 シェルスクリプトの中で書いた場合にはそのシェルスクリプトを終了します。 シェルスクリプト実行中に何らかのエラーが発生した時、その時点で実行をやめたい場合 にこのコマンドを使います。

exit number

exportコマンド

export name

nameで指定した変数を、これ以降に起動した他のコマンドやシェルからも利用できるようになります。

pwdコマンド

カレントディレクトリの絶対パスを表示します。

readコマンド

read variable

キーボードからの入力をvariableという変数にセットします。

#!/bin/sh
echo "enter yes or no --> \c"
read ANSWER
echo $ANSWER
./answer
enter yes or no --> yes
yes

yesという文字をタイプしたので、ANSWERという変数にはyesという文字が代入されます。

readonlyコマンド

readonly name...

nameで指定された変数を書き換え不可にします。

シェルスクリプト中にはあまり使われず、対話的処理の中で、誤って値を変えてしまいたくない 変数に設定します。

returnコマンド

return exitstatus

シェル関数から抜けるコマンドです。exitstatusに指定した番号がその関数の終了コードになります。

指定されなかった場合には、コマンドの実行終了コードが返ります。

setコマンド

sh
sh-3.2$ echo abc
abc
sh-3.2$ set -v
sh-3.2$ echo abc
echo abc
abc
sh-3.2$ set +v
set +v
sh-3.2$ echo abc
abc

setコマンドはシェルのオプションをオンにしたりオフにしたりします。

shiftコマンド

位置パラメタの値を左にずらします。

shiftというファイル名で実行した場合の例です。

cat shift
#!/bin/sh
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
shift
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9
shift aa bb cc dd ee ff gg hh ii
  3  ./shift aa bb cc dd ee ff gg hh ii
./shift aa bb cc dd ee ff gg hh ii
./shift bb cc dd ee ff gg hh ii

引数に数値を指定するとその数だけshiftします。

testコマンド

testコマンドは、ある条件を判定し、正しいか正しくないかによって真(0)偽(0以外)の値を返します。

ファイルに関するオプション

オプション説明
-r filefileが読み取り可なら真
-w filefileが書き込み可なら真
-x filefileが実行可なら真
-f filefileが普通のファイルなら真
-d filefileがディレクトリなら真
-s filefileが0より大きいサイズなら真

文字列に関するオプション

オプション説明
-z stringstringの長さが0なら真
-n stringstringの長さが0より大きいなら真
stringstringがヌルでなければ真
str1 = str2str1とstr2が同じなら真
str1 != str2str1とstr2が同じでないなら真

数値に関するオプション

オプション説明
intl -eq int2int1とint2が等しいなら真
intl -ne int2int1とint2が等しくないなら真
int1 -lt int2int1がint2より小さいなら真
int1 -le int2int1がint2以下なら真
int1 -gt int2int1がint2より大きいなら真
int1 -ge int2int1がint2以上なら真

その他のオプション

オプション説明
!NOTの意味。この直後の判定が偽ならば真
-aAND。前後の判定が真なら真
-oOR。前後の判定のどちらかが真なら真
(expr)グルーピング。判定の優先順を決める
[ -r file -a -w file -a ! -x file ]
# 読み書き可能で、実行不可のfileなら真
[ -d directory -a -x directory ]
# directoryがディレクトリで、移動可能なら真
[ $NUM1 -gt $NUM2 ]
# $NUM1が$NUM2より大きい場合は真
[ "$STRING" != "" ]
# $STRINGに何らかの文字が代入されていれば真
[ $NUM1 -lt $NUM2 -o $NUM1 -gt $NUM3 -a $NUM2 -le $NUM3 ]
# $NUM1が$NUM2より小さいか、または、$NUM1が$NUM3より大きく$NUM2が$NUM3以下の場合真

丸括弧はシェルの特殊文字であるため、クォートしておく必要があります。

ll  # 権限の確認
-rwxrwxrwx  1 jun  staff  108  2 25 21:08 testfile
----------  1 jun  staff    0  2 25 21:13 xxx
cat testfile  # testfileの中身を確認
#!/bin/sh
if [ ! \( -r xxx -a -w xxx \) ]
then
  echo "The file is not readable and writable."
fi
./testfile # testfileを実行すると、xxxが読み書きできないため、if文の中が実行される。
The file is not readable and writable.

trapコマンド

trap action signal...

このシェルスクリプトが、signalに指定したシグナルを受け取ったらどういう処理をするかを actionに指定します。actionはコマンドを並べたものです。

typeコマンド

type name

typeコマンドは、nameで指定したコマンドがどういった種類のシェルか、 コマンド本体のパスはどこかを出力します。

type echo
echo is a shell builtin
echo is /bin/echo
type date
date is /bin/date
type cd
cd is an alias for nocorrect cd
cd is a shell builtin
cd is /usr/bin/cd

umaskコマンド

umask 022

ファイルを作るときにどういう権限で作るかを決定します。

waitコマンド

wait jobnumber

引数にプロセスIDをしてすると、シェルスクリプトの中でバックグラウンドで走らせた 処理が終わるのを待ちます。

引数に何も指定しない場合、そのシェルから派生している子供のプロセス が全部終了するまで待ちます。