Bashスクリプト、パート2:ループ

Bashスクリプト:開始
Bashスクリプト、パート2:ループ
Bashスクリプト、パート3:オプションとコマンドラインスイッチ
Bashスクリプト、パート4:入力と出力
Bashスクリプト、パート5:シグナル、バックグラウンドタスク、スクリプト管理
Bashスクリプト、パート6:関数とライブラリーの開発
Bashスクリプト、パート7:sedとワープロ
Bashスクリプト、パート8:awkデータ処理言語
Bashスクリプトパート9:正規表現
Bashスクリプト、パート10:ケーススタディ
Bashスクリプト、パート11:対話型ユーティリティの期待と自動化

前回 、bashのプログラミングの基本について話しました。 すでに分解されている小さなものでも、誰もがLinuxの作業の自動化を開始できます。 この記事では、bashスクリプトについての話を続け、繰り返しアクションを実行できる制御構造について説明します。 forループとwhileループ、それらの操作方法、およびそれらのアプリケーションの実用的な例について説明しています。

画像

注意:メリットは投稿に隠されています!



forループ


bashシェルはforループをサポートしforます。これにより、値のシーケンスをソートできます。 そのようなループの基本構造は次のとおりです。

 for var in list do  done 

ループの繰り返しごとに、リストの次の値がvar変数に書き込まれます。 したがって、サイクルの最初のパスでは、リストの最初の値が関係します。 サイクルが最後の要素に到達するまで、2番目-2番目などに続きます。

単純な値の列挙


おそらく、bashスクリプトのforループの最も単純な例は、単純な値のリストを反復処理することです。

 #!/bin/bash for var in first second third fourth fifth do echo The  $var item done 

このスクリプトの結果を以下に示します。 リストの要素が$var変数に順番に含まれていることがはっきりとわかります。 これは、サイクルが最後のサイクルに達するまで起こります。


単純なforループ

$var変数は、ループを終了するときに値を保存することに注意してください。その内容は変更できます。一般に、他の変数と同様に操作できます。

複雑な値を反復処理する


forループの初期化に使用されるリストには、1つの単語で構成される単純な行だけでなく、複数の単語と句読点を含むフレーズ全体を含めることができます。 たとえば、これはすべて次のようになります。

 #!/bin/bash for var in first "the second" "the third" "I'll do it" do echo "This is: $var" done 

このサイクルがリストを通過した後は次のようになります。 ご覧のとおり、結果は非常に期待されています。


複雑な値を反復処理する
TNW-CUS-FMP-サービスの10%割引のプロモーションコード。7日以内に有効化できます "

チームの結果から取得したリストを使用したループの初期化


forループを初期化する別の方法は、コマンドの結果であるリストを渡すことです。 ここでは、コマンド置換を使用してそれらを実行し、作業の結果を取得します。

 #!/bin/bash file="myfile" for var in $(cat $file) do echo " $var" done 

この例では、ファイルの内容を読み取るcat使用します。 結果の値のリストがループに転送され、表示されます。 参照しているファイルには、改行文字で区切られた単語のリストが含まれており、空白は使用されていないことに注意してください。


ファイルの内容を反復処理するループ

データの行ごとの処理が予想される場合、このようなアプローチは、行にスペースで区切られた複数の単語が含まれる可能性のある、より複雑な構造のファイルでは機能しないことに注意してください。 ループは、行ではなく単一の単語を処理します。

必要なものがまったくない場合はどうなりますか?

フィールドセパレーター


上記の機能の理由は、フィールドセパレータを指定できるIFS (Internal Field Separator)と呼ばれる特別な環境変数です。 デフォルトでは、bashは次の文字をフィールド区切り文字と見なします。


bashがデータにこれらの文字のいずれかを検出すると、リストの次の独立した値がその前にあると見なします。

問題を解決するために、 IFS環境変数を一時的に変更できます。 以下は、フィールドセパレータとしてラインフィードのみが必要であると仮定して、bashスクリプトでそれを行う方法です。

 IFS=$'\n' 

このコマンドをbashスクリプトに追加すると、フィールドセパレーターのみがラインフィードであると見なし、スペースとタブを無視して、正常に機能します。

 #!/bin/bash file="/etc/passwd" IFS=$'\n' for var in $(cat $file) do echo " $var" done 

このスクリプトを実行すると、必要なものが正確に出力され、ループの各反復で、ファイルに書き込まれた次の行にアクセスできます。


forループでのライントラバーサルによるファイル

区切り文字には他の文字を使用できます。 たとえば、上記では/etc/passwd内容を表示しました。 コロンで区切られた文字列のユーザーデータ。 このような行をループで処理する必要がある場合、 IFSは次のように構成できます。

 IFS=: 

ディレクトリに含まれるファイルの走査


bashスクリプトのforループの最も一般的な使用法の1つは、特定のディレクトリ内のファイルを走査し、これらのファイルを処理することです。

たとえば、ファイルとフォルダをリストする方法は次のとおりです。

 #!/bin/bash for file in /home/likegeeks/* do if [ -d "$file" ] then echo "$file is a directory" elif [ -f "$file" ] then echo "$file is a file" fi done 

この一連の記事から以前の資料を理解したif-thenif-then設計デバイスと、ファイルをフォルダーと区別する方法を理解する必要があります。 上記のコードを理解するのが難しい場合は、この資料をもう一度お読みください。

これは、スクリプトが出力するものです。


フォルダーの内容を一覧表示する

ループを初期化する方法、つまりフォルダーアドレスの末尾のワイルドカード文字「*」に注意してください。 このシンボルは、「任意の名前のすべてのファイル」を意味するテンプレートとして使用できます。 テンプレートに一致するファイル名の自動置換を整理できます。

ifで条件をチェックするとき、変数名を引用符で囲みます。 これは、ファイルまたはフォルダーの名前にスペースが含まれている可能性があるためです。

ループのCスタイル


Cプログラミング言語に精通している場合、bashループfor記述するfor構文は、ループのこのような記述に明らかに慣れているため、奇妙に思えるかもしれません。

 for (i = 0; i < 10; i++) { printf("number is %d\n", i); } 

bashスクリプトでは、 forループを使用できます。forループの説明はCスタイルのループに非常に似ていますが、ここではいくつかの違いがあります。 このアプローチのループ図は次のようになります。

 for ((    ;   ;   )) 

bashでは、次のように記述できます。

 for (( a = 1; a < 10; a++ )) 

そして、これが実際の例です:

 #!/bin/bash for (( i=1; i <= 10; i++ )) do echo "number is $i" done 

このコードは1から10までの数字をリストします。


Cスタイルのワークループ

whileループ


for —コンストラクトfor — 、bashスクリプトでループを編成する唯一の方法でfor —ません。 ここでは、 whileループを使用できます。 このようなサイクルでは、コマンドを指定して特定の条件をチェックし、チェック対象の条件がゼロを返すか、何らかの操作が正常に完了したことを示すシグナルが返されるまで、サイクルの本体を実行できます。 ループ条件がゼロ以外の値、つまりエラーを返すと、ループは停止します。

while
while
do

done
組織図while
while
do

done
次に示します while
while
do

done


このループを使用したスクリプトの例を見てください。

 #!/bin/bash var1=5 while [ $var1 -gt 0 ] do echo $var1 var1=$[ $var1 - 1 ] done 

ループの入り口で、変数$var1ゼロより大きいかどうかがチェックされます。 その場合、ループの本体が実行され、変数の値から1が減算されます。 これは各反復で発生しますが、変数の値は変更される前にコンソールに表示されます。 $var1が0になると、ループは終了します。


whileループの結果

変数$var1変更しないと、スクリプトが無限ループに陥ります。

入れ子ループ


ループの本体では、他のループを実行するなど、任意のコマンドを使用できます。 このような構成は、ネストされたループと呼ばれます。

 #!/bin/bash for (( a = 1; a <= 3; a++ )) do echo "Start $a:" for (( b = 1; b <= 3; b++ )) do echo " Inner loop: $b" done done 

以下は、このスクリプトが出力するものです。 ご覧のとおり、最初に外側のループの最初の反復が実行され、次に内側のループの3つの反復が完了してから、外側のループが再び作用し、次に内側のループが再び作用します。


入れ子ループ

ファイルコンテンツ処理


ほとんどの場合、ネストされたループはファイルの処理に使用されます。 そのため、外側のループはファイルの行を検索し、内側のループはすでに各行で機能しています。 たとえば、 /etc/passwdファイルの処理は次のようになります。

 #!/bin/bash IFS=$'\n' for entry in $(cat /etc/passwd) do echo "Values in $entry –" IFS=: for value in $entry do echo " $value" done done 

このスクリプトには2つのループがあります。 最初は、改行文字をセパレータとして使用して行を調べます。 内側のものは、フィールドがコロンで区切られた文字列の解析です。


ファイルデータ処理

このアプローチは、CSV形式のファイル、または同様のファイルを処理し、必要に応じてIFS環境変数に区切り文字を書き込むときに使用できます。

サイクル管理


おそらく、ループに入った後、ループ変数がループを終了するために最初に指定された条件に対応しない特定の値に達したときにループを停止する必要があります。 そのような状況では、サイクルの正常な完了を待つ必要がありますか? いいえ、もちろん、そのような場合、次の2つのコマンドが役立ちます。


ブレークコマンド


このコマンドを使用すると、ループの実行を中断できます。 forループとwhileループの両方for使用できます。

 #!/bin/bash for var1 in 1 2 3 4 5 6 7 8 9 10 do if [ $var1 -eq 5 ] then break fi echo "Number: $var1" done 

このようなサイクルは、通常の条件下では、リストから値のリスト全体を通過します。 ただし、この例では、変数$var1が5に等しいときに実行が中断されます。


forループの早期終了

これも同じですが、 while

 #!/bin/bash var1=1 while [ $var1 -lt 10 ] do if [ $var1 -eq 5 ] then break fi echo "Iteration: $var1" var1=$(( $var1 + 1 )) done 

$var1の値が5になったときに実行されるbreakコマンドは、ループを中断します。 コンソールには、前の例と同じものが表示されます。

続行コマンド


ループの本体でこのコマンドが検出されると、現在の反復はスケジュールより早く終了し、次の反復が開始されますが、ループの終了は発生しません。 forループのcontinueコマンドを見てみましょう。

 #!/bin/bash for (( var1 = 1; var1 < 15; var1++ )) do if [ $var1 -gt 5 ] && [ $var1 -lt 10 ] then continue fi echo "Iteration number: $var1" done 

ループ内の条件が満たされると、つまり$var1 5より大きく10より小さいと、シェルはcontinueコマンドを実行します。 これにより、ループ本体の残りのコマンドが省略され、次の反復に移行します。


forループでコマンドを続行します

ループ出力処理


ループに表示されるデータは、出力をリダイレクトするか、パイプラインに渡すことで処理できます。 これを行うには、 doneステートメントの後に出力処理コマンドを追加します。

たとえば、ループに表示されるものを画面に表示する代わりに、これをすべてファイルに書き込むか、別の場所に転送できます。

 #!/bin/bash for (( a = 1; a < 10; a++ )) do echo "Number is $a" done > myfile.txt echo "finished." 

シェルはmyfile.txtファイルを作成し、 forコンストラクトの出力をこのファイルにリダイレクトします。 ファイルを開き、期待どおりのものが正確に含まれていることを確認します。


ループ出力をファイルにリダイレクトする

例:実行可能ファイルの検索


すでに分解したものを利用して、有用なものを書きましょう。 たとえば、システムで使用可能な実行可能ファイルを正確に調べる必要がある場合、PATH環境変数に書き込まれたすべてのフォルダーをスキャンできます。 このために必要な資金は既にすべて揃っています。すべてをまとめる必要があるだけです。

 #!/bin/bash IFS=: for folder in $PATH do echo "$folder:" for file in $folder/* do if [ -x $file ] then echo " $file" fi done done 

小さくて複雑でないこのようなスクリプトにより、 PATHからフォルダーに保存されている実行可能ファイルのリストを取得することができました。


PATH変数からフォルダー内の実行可能ファイルを検索する

まとめ


今日は、bashスクリプトのforループとwhileループ、それらの実行方法、管理方法について説明しました。 これで、異なる区切り文字を持つ行をサイクルで処理する方法、サイクルで表示されたデータをファイルにリダイレクトする方法、ディレクトリの内容を表示および分析する方法がわかりました。

あなたがこの連載の第1部と第2部で紹介されている内容のみを知っているbashスクリプトの開発者であると想定している場合は、すでに有用なものを書くことができます。 3つ目のパートは、パラメータとコマンドラインスイッチをbashスクリプトに渡す方法と、すべての対処方法を理解した後の3番目のパートです。

親愛なる読者! 前の記事へのコメントであなたは私たちに多くの興味深いことを言った。 これはすべて、bashのプログラミング方法を学びたい人にとって非常に貴重なものになると確信しています。 しかし、このトピックは非常に大きいので、経験豊富な人たちに経験を共有し、初心者にも印象を伝えてください。

Source: https://habr.com/ru/post/J325928/


All Articles