bash関数の一般的に使用される(または不当にまれに使用される)ユーティリティ「ライブラリ」はありますか?Java 用の Apache commons-lang のようなもの。Bash はどこにでもあるので、拡張ライブラリの領域では奇妙に無視されているように見えます。
6 に答える
bash 用のライブラリはありますが、一般的ではありません。bash ライブラリが不足している理由の 1 つは、機能の制限によるものです。これらの制限は、「Greg's Bash Wiki」で最もよく説明されていると思います。
機能。Bash の「関数」にはいくつかの問題があります。
コードの再利用性: Bash 関数は何も返しません。出力ストリームのみを生成します。そのストリームをキャプチャし、それを変数に割り当てるか、引数として渡すには、すべての合理的な方法で SubShell が必要です。これにより、外部スコープへのすべての割り当てが中断されます。(関数から結果を取得するためのトリックについては、BashFAQ/084 も参照してください。) したがって、名前が引数として渡される変数に結果を格納するように関数に要求することはできないため、再利用可能な関数のライブラリは実行できません (例外を除く)。評価バックフリップを実行することによって)。
スコープ: Bash には、"動的スコープ" (Javascript、elisp など) にほぼ似たローカル スコープの単純なシステムがあります。関数は呼び出し元のローカルを認識しますが (Python の「非ローカル」キーワードのように)、呼び出し元の位置パラメーターにアクセスすることはできません (extdebug が有効になっている場合は BASH_ARGV を使用する場合を除く)。再利用可能な関数は名前空間の衝突がないことを保証することはできません. これは、n-2 で再利用可能な関数によって上書きされた可能性のあるフレーム n-3 の変数名に作用することを期待する関数を実装する場合に特に問題になります。Ksh93 は、「関数名 { ... }」構文で関数を宣言することにより、より一般的なレキシカル スコープ規則を使用できます (Bash はできませんが、とにかくこの構文をサポートしています)。
クロージャ: Bash では、関数自体は常にグローバル (「ファイル スコープ」を持つ) であるため、クロージャはありません。関数定義は入れ子にすることができますが、見た目はほとんど同じですが、これらはクロージャーではありません。関数は「通過可能」(ファーストクラス) ではなく、無名関数 (ラムダ) はありません。実際、特に配列では、「通用する」ものはありません。Bash は厳密に値による呼び出しのセマンティクスを使用します (マジック エイリアス ハックを除く)。
以下を含む多くの複雑な問題があります。エクスポートされた関数; 「関数の崩壊」(他の関数またはそれ自体を定義または再定義する関数); トラップ (およびその継承); 関数が stdio と対話する方法。これらすべてを理解していないことで初心者を噛まないでください。シェル関数は完全にめちゃくちゃです。
ソース: http://mywiki.wooledge.org/BashWeaknesses
シェル「ライブラリ」の一例は、Redhat ベースのシステムの /etc/rc.d/functions です。このファイルには、sysV init スクリプトで一般的に使用される関数が含まれています。
local
関数内で宣言されているがキーワードがない変数はグローバルです。
他の関数やグローバルとの競合を避けるために、関数内でのみ必要な変数を宣言することをお勧めしますlocal
(下記の foo() を参照)。
Bash 関数ライブラリは、常に「ソース化」する必要があります。私は、より一般的なドット (.) の代わりに「ソース」シノニムを使用することを好みます。これにより、デバッグ中に見やすくなります。
次の手法は、少なくとも bash 3.00.16 および 4.1.5 で機能します...
#!/bin/bash
#
# TECHNIQUES
#
source ./TECHNIQUES.source
echo
echo "Send user prompts inside a function to stderr..."
foo() {
echo " Function foo()..." >&2 # send user prompts to stderr
echo " Echoing 'this is my data'..." >&2 # send user prompts to stderr
echo "this is my data" # this will not be displayed yet
}
#
fnRESULT=$(foo) # prints: Function foo()...
echo " foo() returned '$fnRESULT'" # prints: foo() returned 'this is my data'
echo
echo "Passing global and local variables..."
#
GLOBALVAR="Reusing result of foo() which is '$fnRESULT'"
echo " Outside function: GLOBALVAR=$GLOBALVAR"
#
function fn()
{
local LOCALVAR="declared inside fn() with 'local' keyword is only visible in fn()"
GLOBALinFN="declared inside fn() without 'local' keyword is visible globally"
echo
echo " Inside function fn()..."
echo " GLOBALVAR=$GLOBALVAR"
echo " LOCALVAR=$LOCALVAR"
echo " GLOBALinFN=$GLOBALinFN"
}
# call fn()...
fn
# call fnX()...
fnX
echo
echo " Outside function..."
echo " GLOBALVAR=$GLOBALVAR"
echo
echo " LOCALVAR=$LOCALVAR"
echo " GLOBALinFN=$GLOBALinFN"
echo
echo " LOCALVARx=$LOCALVARx"
echo " GLOBALinFNx=$GLOBALinFNx"
echo
ソース関数ライブラリは次のように表されます...
#!/bin/bash
#
# TECHNIQUES.source
#
function fnX()
{
local LOCALVARx="declared inside fnX() with 'local' keyword is only visible in fnX()"
GLOBALinFNx="declared inside fnX() without 'local' keyword is visible globally"
echo
echo " Inside function fnX()..."
echo " GLOBALVAR=$GLOBALVAR"
echo " LOCALVARx=$LOCALVARx"
echo " GLOBALinFNx=$GLOBALinFNx"
}
TECHNIQUES を実行すると、次の出力が生成されます...
Send user prompts inside a function to stderr...
Function foo()...
Echoing 'this is my data'...
foo() returned 'this is my data'
Passing global and local variables...
Outside function: GLOBALVAR=Reusing result of foo() which is 'this is my data'
Inside function fn()...
GLOBALVAR=Reusing result of foo() which is 'this is my data'
LOCALVAR=declared inside fn() with 'local' keyword is only visible in fn()
GLOBALinFN=declared inside fn() without 'local' keyword is visible globally
Inside function fnX()...
GLOBALVAR=Reusing result of foo() which is 'this is my data'
LOCALVARx=declared inside fnX() with 'local' keyword is only visible in fnX()
GLOBALinFNx=declared inside fnX() without 'local' keyword is visible globally
Outside function...
GLOBALVAR=Reusing result of foo() which is 'this is my data'
LOCALVAR=
GLOBALinFN=declared inside fn() without 'local' keyword is visible globally
LOCALVARx=
GLOBALinFNx=declared inside fnX() without 'local' keyword is visible globally
ユーティリティライブラリの包括的なリストを提供する、古き良き記事をここで見つけました。
http://dberkholz.com/2011/04/07/bash-shell-scripting-libraries/