やあ! HowToForgeのシェルスクリプトチュートリアルシリーズへようこそ。チュートリアルの以前のリリースを読みたい場合は、チュートリアルのパート1、パート2、パート3、およびパート4についてはここをクリックしてください。このパートでは、関数を作成してスクリプトを効率的に構造化する方法を学習します。このチュートリアルを終了するまでに、LinuxのBashシェルで関数を作成し、関数にパラメーターを渡し、関数からメインコードにいくつかの値を返す方法を理解できるようになります。始めましょう!
プログラミング言語ではサブルーチンとも呼ばれる関数は、メインルーチンの特定のタスクを実行する一連の命令です[1]。これにより、プログラマーは複雑で長いコードを小さなセクションに分割し、必要なときにいつでも呼び出すことができます。各関数は、実行するためにメインルーチンによって呼び出される必要があります。したがって、関数はコードの他の部分と分離されており、コードテストの簡単な方法を作成します。さらに、関数はいつでも繰り返し呼び出すことができるため、コードを再利用、最適化、および最小化できます。ほとんどのプログラミング言語と同様に、bashシェルも関数をサポートしています。
一般的な構文:
- 構文1:
function function_name
{
##### set of commands
} - 構文2:
function_name()
{
#### set of commands
}
bashは、関数の2つの構造をサポートします。最初の構文を使用する場合は、キーワードfunctionを使用し、その後に関数名を使用し、括弧と中括弧を開いたり閉じたりして、関数の内容をメインルーチンに区切る必要があります。 PHPの関数は同じ方法で宣言されるため、PHPのバックグラウンドがある場合は、この構文に慣れているでしょう。もう1つの構文は、関数名、開き括弧と閉じ括弧、および中括弧のみで構成されます。
#!/bin/bash
myfunction(){
echo "My function works!"
}
myfunction
この例では、2番目の構文を使用しました。関数myfunctionを作成した後、その関数名をメインルーチンに呼び出すことによって呼び出されました。メインルーチンは、関数の一部として定義されていないスクリプト内の任意の場所にあります。
次に、コードを再配置して、スクリプト内のどこでも関数を宣言できるかどうかをテストしましょう。以下のコードを検討してください:
#!/bin/bash
echo "testing my function"
myfunction
myfunction(){
echo "My function works!"
}
上記のコードの3行目は、コマンドが見つからないというエラーを返します。これは、次のことを意味するだけです:
The function only works if it is declared before your main routine. The interpreter will return an error if you have declared your function after your main routine.
関数の最も優れた機能の1つは、コードを再利用できることです。プロシージャでコマンドを繰り返し実行する必要があるが、ループステートメントを使用して構造化できない場合は、関数が解決策になる可能性があります。
たとえば、次のコードについて考えてみます。
#!/bin/bash
while(true)
do
clear
printf "Choose from the following operations: \n"
printf "[a]ddition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n"
printf "################################\n"
read -p "Your choice: " choice
case $choice in
[aA])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1+int2))
;;
[bB])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1-int2))
;;
[cC])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1*int2))
;;
[dD])
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
res=$((int1/int2))
;;
*)
res=0
echo "wrong choice!"
esac
echo "The result is: " $res
read -p "Do you wish to continue? [y]es or [n]o: " ans
if [ $ans == 'n' ]
then
echo "Exiting the script. Have a nice day!"
break
else
continue
fi
done
スクリプトは正常に実行されていますが、入力を受け入れるための行は、switchステートメントの各パターンで繰り返し実行されていることに注意してください。
#!/bin/bash
inputs(){
read -p "Enter first integer: " int1
read -p "Enter second integer: " int2
}
exitPrompt(){
read -p "Do you wish to continue? [y]es or [n]o: " ans
if [ $ans == 'n' ]
then
echo "Exiting the script. Have a nice day!"
break
else
continue
fi
}
while(true)
do
clear
printf "Choose from the following operations: \n"
printf "[a]Addition\n[b]Subtraction\n[c]Multiplication\n[d]Division\n"
printf "################################\n"
read -p "Your choice: " 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 "wrong choice!"
esac
echo "The result is: " $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 "Enter an integer: " int1
read -p "Enter an integer: " int2
add $int1 $int2
echo "The result is: " $?
この例では、パラメーターint1とint2をadd関数に渡します。次に、add関数はsum =$(($ 1 + $ 2))の行を介してそれを処理します。次に、sum変数の値は、行return$sumを介してメインルーチンに渡されます。デフォルトでは、$ sumの値はデフォルトの変数$?に格納されます。最後に、行echo "結果は次のとおりです:" $?結果を出力します。
Note: Shell scripts can only return a single value.
他のプログラミング言語とは異なり、シェルスクリプトは関数から複数の値を返すことはできません。この例を見てみましょう:
#!/bin/bash
add(){
sum=$(($1+$2))
dif=$(($1-$2))
return $sum
}
read -p "Enter an integer: " int1
read -p "Enter an integer: " int2
add $int1 $int2
echo "The result is: " $?
echo "The result is: " $?
関数を使用し、パラメーターを渡して値を返す別の例を見てみましょう。
#!/bin/bash
#####################
#Author: HowtoForge #
#####################
clear(){
clear
}
bin(){
bin1=$(echo "obase=2;$1"|bc)
echo $bin1
}
dec(){
dec1=$(echo "ibase=2;$1"|bc)
return $dec1
}
########Main#########
printf "Choose from the following operations:\n[1]Decimal to Binary Conversion\n"
printf "[2]Binary to Decimal Conversion\n"
read -p "Your choice: " op
case $op in
1)
read -p "Enter integer number: " int
bin $int
;;
2)
read -p "Enter binary number: " int
dec $int
echo "The decimal equivalent of $int is $?"
;;
*)
echo "Wrong Choice!"
esac
与えられた例は、obaseおよびibaseコマンドを使用して、与えられた入力を2進値または10進値の両方に変換します。行$(echo "obase =2; $ 1" | bc)は、指定された10進値を2進数に変換し、それをbin1変数に格納します。次に、echoコマンドを使用して$bin1の値を表示しました。
Note: It's better to use echo directly when converting from decimal to binary because when you return command to pass a binary value, the bash converts the binary value to decimal before returning it.
さらに、コマンド$(echo "ibase =2; $ 1" | bc)を使用して2進値を10進数に変換しました。
また、インタプリタは8ビットの2進数しか受け入れることができないことを覚えておく必要があります。 8ビットの制限を超える桁を入力すると、オーバーフローが発生し、桁の最上位ビットが破棄されます。
10ビットの2進数1000001010は、8ビットの規則に従って10を返します。これは、右側の残りの2ビット(最上位ビット)が省略されるため、1000001010は00001010に等しくなり、10に等しくなります。 8ビットを超える2進数を受け入れる操作が必要な場合は、コードを手動で作成する必要があります。
Bashにはプログラミング言語と非常によく似た機能があり、ユーザーに多数のツールを提供し、Linuxシステムをより強力にします。このシリーズでは、関数を使用してシェルスクリプトの知識を深めました。シェルスクリプトで機能し、ユーザーにモジュール性を提供して、スクリプトのトラブルシューティングを容易にし、コードの再利用を可能にします。