高級言語、スクリプト言語、インタプリタ言語:xxx.sh、一般的に bash に基づく
コース内容#
最初のシェルスクリプト#
#!/bin/bash
#コメント
echo "Hello"
- 最初の行 #! はインタプリタを指定し、最初の行でのみ有効
- コメント:"#"
変数#
a=123
a=hello
a=`pwd`
PATH=${PATH}:path # 変数の後に文字列を付けることができ、文字列を直接結合できる
# 【注意】":a"には特別な意味があり、現在のパスを指す
特殊変数#
位置変数
結果:
-
$n:n が 9 より大きい場合、大括弧で囲む必要がある
-
$@ と $* の違いは:渡された引数がそれぞれ二重引用符で囲まれ、かつ $ 変数も二重引用符で囲まれている場合、"$@" はすべての引数を分ける【一般的な場合】が、"$*" はすべての引数を一つの全体として扱う
- for...in を使用する際に見ることができる、詳細はシェル特殊変数:Shell $0, $#, $*, $@, $?, $$ とコマンドライン引数——C 言語中文網
-
$#:$0 はカウントしない
状態変数
- $?:【前の】コマンドの実行結果、0—— 成功、非 0—— 失敗
- スクリプトがコマンドの成功を自動的に判断するのに便利
- $$、$!:現在のプロセス、最後に実行されたバックグラウンドプロセスの PID、一般的に自動化テストや複数スクリプトのインタラクションシーンで使用される
入力と出力#
- 入力:read
- -p:フレンドリーなプロンプトを表示、bash で使用する必要がある
- -s:サイレントモード
- -t:入力待機時間、タイムアウト終了(単位:s)
- 出力:echo
- -e:エスケープを有効にする
- 出力:printf
- C 言語の printf に非常に似ている!
- [PS] ! と \n を一緒に使うと特別な意味があるため、分ける必要がある
- bash では分ける必要がある
- zsh では分けることができるか、\ でエスケープすることができる
- 一般的に特殊記号—— 菜鳥教程に注意が必要!
関数#
-
引数はない
-
定義:書き方は多く、function、()、{} の組み合わせ、3 番目の方法は C 言語の書き方に似ている
-
呼び出し:関数名 引数...
- function を加えることで読みやすくなる
-
❗【注意】シェルの関数 return の返り値には制限があり、範囲は 0-255、オーバーフローすると循環計算される
フロー制御#
do——done、if——then——fi、case——esac
【重要】TEST 式⭐#
- 型を判断できる:文字列、整数、ファイル
- ❗ 【注意】条件が真のとき、0 を返し、そうでない場合は非 0 を返す
- Linux のコマンドの返り値も同様で、0 が成功を示す
- [PS]
- STRING1 = STRING2 は == でも可能【後者を推奨、二重括弧 [[]] がサポートされている】
- -G FILE:ファイルが存在し、かつ有効なグループ ID に所有されている
- グループが解散された場合、そのグループが管理するファイルのグループ ID は無効になる
- 詳細は man マニュアルを参照:man test
分岐構造#
if
-
if は二重括弧 [[]] の書き方を使用し、より高度で TEST 式との互換性が良い
- 一重括弧 [ ] は多くの年前の書き方であり、推奨されず、二重括弧を使用すること
- 参考:Linux Shell の ()、(())、[]、[[]]、{} の役割—— ブログ
case
-
セミコロン;;は必ず必要!break に相当し、break を加えた場合も必要
-
デフォルトの状況は *) を使用できる
-
case はあまり使用されず、一般的にメニューを作成するために使用され、if よりも美しい
ループ構造#
for
-
seq を利用してシーケンスを生成
-
ls のマッチングルールを利用
-
for の 2 つの形式
-
二重小括弧 (()) の中の内容は C 言語の演算ルールに従う限り、変数の前に $ を付ける必要はなく、i++ と書くことができ、通常は ++ を使用できない
while
-
同様に test 式が適用される
-
num 変数を初期化しないと
- 最初の echo $num 時、$num は空値であり、空行として表示される
- 後の + 1 に遭遇したとき、システムはそれを整数型として判断し、整数として扱う
until
-
while との唯一の違いは:until は停止条件を書き、while はループ条件を書く
配列#
-
配列の代入【方法①】と呼び出し
-
【一般的な配列操作】は配列要素のインデックスを出力することもできる、後で見て
-
配列を宣言する:declare -a num、読みやすくするため、宣言しなくても可能【弱い型の言語】
-
代入【方法②、③】
- num[2]=10 num[5]=7 num[100]=3.2.4
- num=(1 a b 10)
-
配列要素は必ずしも連続して代入する必要はなく、任意の型を持つことができる
- 【一般的な配列操作】加!:すべての配列要素に対応するインデックスを出力し、連続していないことがわかる
【その他の配列操作】
-
+=:追加
-
unset:配列または要素を削除する【インデックスで削除】
-
[PS] 代入方法③は複数の空白も 1 つの区切り文字として扱う
応用
-
ファイル名リストを保存するために使用できる
-
【注意】代入方法③で配列に代入する際は空白を区切り文字として使用するため、ファイル名に空白が含まれている場合は特別な処理が必要
-
【PS】素数フィルタ、線形フィルタ
授業の練習#
1~100 の偶数の合計#
-
$[ ] は整数演算に使用できる
-
seq は効率がやや低い
力任せに素数を求める#
-
関数の return 値
- $? を通じて得られ、関数を呼び出した後に echo $? を実行すればよいが、return 値には範囲制限がある 0~255!
- コマンド置換符 `` を使用して取得する
-
ループ変数 i の衝突問題に注意:ローカル変数を定義する
-
🆒プログラムのデバッグ
- 習慣:適度な echo 出力
- グローバルデバッグ:bash -x *.sh
- ローカルデバッグ:set -x [デバッグコード領域] set +x
素数フィルタ#
-
方法一は素数を操作するのに便利で、出力時に判断を減らすことができる
-
方法二は合成数を操作することもできる
【力任せ法、素数フィルタの 2 つの方法の効果比較】2~10000 の素数の合計を求める
- 9.prime.sh 力任せ法 —— 10.prime.sh 素数フィルタ
追加の知識点#
- .sh スクリプトは直接 bash または source で実行でき、./ を使用するには実行権限が必要
- source、sh、bash、./ の違い——cnblogs
- set -x はシェルデバッグを有効にする
- シェルコマンド置換:コマンドの出力結果を変数に代入する——C 言語中文網
- $() はネストをサポートし、バッククオート `` はサポートしない
- $() は Bash でのみ有効【zsh、sh もサポートしているようだ】、バッククオート `` は多くのシェルで使用可能
- 二重小括弧 (()) の中の内容
- C 言語の演算ルールに従う限り
- 変数の前に $ を付ける必要はない
- i++ と書くことができ、通常は ++ を使用できない
- ⭐シェルでは、変数がまだ定義されていない場合、その値は空であり、echo 出力は空行として表示される
- ⭐空白の問題【厳密】
- 代入文:= の左右には空白を含めてはいけない
- TEST 式関連:[[]] の両端には空白が必要
- 変数名 i について、$i と_i を結合したい場合、$i_i と書くと変数 i_i を探しに行くため、${i}_i を使用する必要がある
ヒント#
- シェルスクリプトを書く際
- 性能をあまり考慮せず、単純に数学計算の効率は低い
- 問題を迅速に解決するために、すべてのタスクのフローを計画するために使用する
- 操作の前に【バックアップ】操作を加えることを忘れない
- 一般的にはシステムに作業をさせることが多く、特定のプログラムに作業をさせるのは難しい
- プログラムは一般的に独自のパラメータ設定を持っているが、普遍性はない
- API は一般的にサービスを指す
- ⭐シェルスタイルガイド——Google オープンソースプロジェクトスタイルガイド —— シェルプログラミング規範
- シェルスクリプトの複数行コメントと単行コメントの方法—— ブログ
:<<!
[コメントするコード]
!
- let—— 菜鳥教程を理解すると便利な構文