シェルスクリプト · 2 min read · Dec 07, 2025
シェルスクリプト パートV: Bashにおける関数
こんにちは!HowToForgeのシェルスクリプトチュートリアルシリーズへようこそ。チュートリアルの前のリリースを読みたい場合は、こちらをクリックしてパート1、パート2、パート3、パート4をご覧ください。このパートでは、関数を作成することでスクリプトを効率的に構造化する方法を学びます。このチュートリアルの終わりまでには、Linux Bashシェルで関数を作成し、関数にパラメータを渡し、関数からメインコードに値を返す方法を理解できるようになります。それでは始めましょう!
はじめに
関数は、プログラミング言語におけるサブルーチンとも呼ばれ、特定のタスクをメインルーチンのために実行する命令のセットです[1]。これにより、プログラマーは複雑で長いコードを必要に応じて呼び出すことができる小さなセクションに分割できます。各関数は実行するためにメインルーチンによって呼び出される必要があるため、コードの他の部分とは隔離されており、これによりコードのテストが容易になります。さらに、関数はいつでも繰り返し呼び出すことができるため、コードを再利用、最適化、最小化することができます。ほとんどのプログラミング言語と同様に、bashシェルも関数をサポートしています。
一般的な構文:
- 構文1:
function function_name { ##### コマンドのセット } - 構文2:
function_name() { #### コマンドのセット }
関数の作成
bashは関数のために2つの構造をサポートしています。最初の構文を使用する場合は、キーワードfunctionを使用し、その後に関数名と開きおよび閉じの括弧、波括弧を使用して関数の内容をメインルーチンから分ける必要があります。この構文は、PHPのバックグラウンドがある場合には馴染みがあるでしょう。なぜなら、PHPの関数は同じ方法で宣言されるからです。もう一つの構文は、関数名、開きおよび閉じの括弧、波括弧のみで構成されています。
#!/bin/bash
myfunction(){
echo "My function works!"
}
myfunction
私たちの例では2番目の構文を使用しました。myfunctionを作成した後、関数名を呼び出すことでメインルーチンに呼び出されました。メインルーチンは、関数の一部として定義されていないスクリプト内のどこにでも存在します。
次に、関数がスクリプト内のどこでも宣言できるかどうかをテストするためにコードを再配置してみましょう。以下のコードを考えてみてください:
#!/bin/bash
echo "testing my function"
myfunction
myfunction(){
echo "My function works!"
}
上記のコードの3行目は「コマンドが見つかりません」というエラーを返します。これは次のことを意味します:
関数はメインルーチンの前に宣言されている場合にのみ機能します。メインルーチンの後に関数を宣言した場合、インタープリターはエラーを返します。関数を使用したコードの再構成
関数の最も優れた機能の1つは、コードを再利用できることです。手続きがコマンドを繰り返し実行する必要があるが、ループ文を使用して構造化できない場合、関数が解決策となります。
例えば、以下のコードを考えてみてください:
#!/bin/bash
while(true)
do
clear
printf "次の操作から選択してください: \n"
printf "[a]加算\n[b]減算\n[c]乗算\n[d]除算\n"
printf "################################\n"
read -p "あなたの選択: " choice
case $choice in
[aA])
read -p "最初の整数を入力してください: " int1
read -p "2番目の整数を入力してください: " int2
res=$((int1+int2))
;;
[bB])
read -p "最初の整数を入力してください: " int1
read -p "2番目の整数を入力してください: " int2
res=$((int1-int2))
;;
[cC])
read -p "最初の整数を入力してください: " int1
read -p "2番目の整数を入力してください: " int2
res=$((int1*int2))
;;
[dD])
read -p "最初の整数を入力してください: " int1
read -p "2番目の整数を入力してください: " int2
res=$((int1/int2))
;;
*)
res=0
echo "無効な選択!"
esac
echo "結果は: " $res
read -p "続けますか? [y]はい または [n]いいえ: " ans
if [ $ans == 'n' ]
then
echo "スクリプトを終了します。良い一日を!"
break
else
continue
fi
done
スクリプトは正常に動作していますが、スイッチ文の各パターンで入力を受け付ける行が繰り返されていることに注意してください。
#!/bin/bash
inputs(){
read -p "最初の整数を入力してください: " int1
read -p "2番目の整数を入力してください: " int2
}
exitPrompt(){
read -p "続けますか? [y]はい または [n]いいえ: " ans
if [ $ans == 'n' ]
then
echo "スクリプトを終了します。良い一日を!"
break
else
continue
fi
}
while(true)
do
clear
printf "次の操作から選択してください: \n"
printf "[a]加算\n[b]減算\n[c]乗算\n[d]除算\n"
printf "################################\n"
read -p "あなたの選択: " choice
case $choice in
[aA])
inputs
res=$((int1+int2))
;;
[bB])
inputs
res=$((int1-int2))
;;
[cC])
inputs
res=$((int1*int2))
;;
[dD])
inputs
res=$((int1/int2))
;;
*)
res=0
echo "無効な選択!"
esac
echo "結果は: " $res
exitPrompt
done
私たちは、inputsとexitPromptというサブセクションを作成することでコードを改善しました。これは以前のコードと全く同じように動作しますが、現在のコードは適切に構造化されているため、トラブルシューティングが容易です。
関数へのパラメータの渡し方
ほとんどのプログラミング言語と同様に、bashの関数にパラメータを渡し、それらのデータを処理することができます。以下のコードは、シェルスクリプトで値を渡す手順を示しています:
#!/bin/bash
myfunction(){
echo $1
echo $2
}
myfunction "Hello" "World"
私たちの例では、myfunctionを呼び出した後に「Hello」と「World」という値を追加しました。これらの値は、パラメータとしてmyfunctionに渡され、ローカル変数に格納されます。ただし、他の言語とは異なり、インタープリターは渡された値を事前定義された変数に格納します。これらの変数は、パラメータの渡し方に応じて名前が付けられ、1が最初の名前で、渡された順序に従います。「Hello」という単語は変数1に格納され、「World」という値は変数2に格納されます。
注意: 例の1と2はローカル変数であり、したがって、パラメータが渡される関数以外のスクリプトの他の部分からはアクセスできません。
例えば、
#!/bin/bash
myfunction(){
echo $1
echo $2
}
myfunction "Hello" "World"
echo $1
echo $2
スクリプトの最後の2行のecho $1とecho $2は表示されません。なぜなら、インタープリターは両方の変数を認識しないからです。これらはmyfunctionにローカルです。
関数からの値の返却
関数を作成し、パラメータを渡すことに加えて、bashの関数はキーワードreturnを使用して関数のローカル変数の値をメインルーチンに渡すことができます。返された値はデフォルトの変数$?に格納されます。例えば、以下のコードを考えてみてください:
#!/bin/bash
add(){
sum=$(($1+$2))
return $sum
}
read -p "整数を入力してください: " int1
read -p "整数を入力してください: " int2
add $int1 $int2
echo "結果は: " $?
この例では、int1とint2のパラメータをadd関数に渡します。次に、add関数はsum=$(($1+$2))の行を通じてそれを処理します。次に、sum変数の値はreturn $sumの行を通じてメインルーチンに渡されます。デフォルトでは、$sumの値はデフォルトの変数$?に格納されます。最後に、echo “結果は: “ $?の行が結果を印刷します。
注意: シェルスクリプトは単一の値しか返すことができません。他のプログラミング言語とは異なり、シェルスクリプトは関数から複数の値を返すことができません。以下の例を見てみましょう:
#!/bin/bash
add(){
sum=$(($1+$2))
dif=$(($1-$2))
return $sum
}
read -p "整数を入力してください: " int1
read -p "整数を入力してください: " int2
add $int1 $int2
echo "結果は: " $?
echo "結果は: " $?
まとめ
関数を使用し、パラメータを渡し、値を返す別の例を見てみましょう。
#!/bin/bash
#####################
#著者: HowtoForge #
#####################
clear(){
clear
}
bin(){
bin1=$(echo "obase=2;$1"|bc)
echo $bin1
}
dec(){
dec1=$(echo "ibase=2;$1"|bc)
return $dec1
}
########メイン#########
printf "次の操作から選択してください:\n[1]10進数から2進数への変換\n"
printf "[2]2進数から10進数への変換\n"
read -p "あなたの選択: " op
case $op in
1)
read -p "整数を入力してください: " int
bin $int
;;
2)
read -p "2進数を入力してください: " int
dec $int
echo "$intの10進数は$?です"
;;
*)
echo "無効な選択!"
esac

この例では、与えられた入力を2進数または10進数の値に変換します。$(echo “obase=2;$1”|bc)の行は、与えられた10進数の値を2進数の桁に変換し、bin1変数に格納します。次に、echoコマンドを使用して$bin1の値を表示します。
注意: 10進数から2進数に変換する際は、直接echoを使用する方が良いです。なぜなら、バイナリ値を渡すためにreturnコマンドを使用すると、bashは返す前にバイナリ値を10進数に変換するからです。さらに、$(echo “ibase=2;$1”|bc)コマンドを使用して2進数の値を10進数に変換しました。
インタープリターは8ビットの2進数桁しか受け付けられないことも覚えておく必要があります。8ビットの制限を超える桁を入力すると、オーバーフローが発生し、桁の最上位ビットが破棄されます。
10ビットの2進数桁1000001010は10を返します。なぜなら、8ビットのルールに従い、右側の残りの2ビット(最上位ビット)が省略されるため、1000001010は00001010と等しくなり、10になります。8ビットを超える2進数桁を受け入れる操作を行いたい場合は、コードを手動で作成する必要があります。
結論
Bashは、ユーザーに多数のツールを提供し、Linuxシステムをより強力にするために、プログラミング言語に非常に似た機能を持っています。このシリーズでは、関数を通じてシェルスクリプトの知識を深めました。シェルスクリプトの関数は、ユーザーにモジュール性を提供し、スクリプトのトラブルシューティングを容易にし、コードの再利用を可能にします。
参考文献:
[1] American Heritage® Dictionary of the English Language, Fifth Edition. Copyright © 2011 by Houghton Mifflin Harcourt Publishing Company. Published by Houghton Mifflin Harcourt Publishing Company.
新しい投稿を受信箱で受け取る
スパムはありません。いつでも購読を解除できます。