Zaten aşağıdaki yöntemlerin birkaç kez nasıl çalıştığını ve nedenlerini tartıştım, bu yüzden tekrar yapmayacağım. Şahsen, konuyla ilgili kendi favorilerim burada ve burada .
Bunu okumakla ilgilenmiyorsanız, ancak hala işlevin girdisine eklenen burada bulunan belgelerin, işlev çalışmadan önce kabuk genişletme için değerlendirildiğini ve işlev tanımlandığında bulundukları durumda yeniden oluşturulduğunu anlayın. her zaman fonksiyonu olarak adlandırılır.
BİLDİRMEK
Sadece diğer işlevleri bildiren bir işleve ihtiyacınız var.
_fn_init() { . /dev/fd/4 ; } 4<<INIT
${1}() { $(shift ; printf %s\\n "$@")
} 4<<-REQ 5<<-\\RESET
: \${_if_unset?shell will ERR and print this to stderr}
: \${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init $(printf "'%s' " "$@")
RESET
INIT
ÇALIŞTIR
İşte ben çağırıyorum _fn_init
bana bir fonksiyon bildirmeyefn
.
set -vx
_fn_init fn \
'echo "this would be command 1"' \
'echo "$common_param"'
#OUTPUT#
+ _fn_init fn 'echo "this would be command 1"' 'echo "$common_param"'
shift ; printf %s\\n "$@"
++ shift
++ printf '%s\n' 'echo "this would be command 1"' 'echo "$common_param"'
printf "'%s' " "$@"
++ printf ''\''%s'\'' ' fn 'echo "this would be command 1"' 'echo "$common_param"'
#ALL OF THE ABOVE OCCURS BEFORE _fn_init RUNS#
#FIRST AND ONLY COMMAND ACTUALLY IN FUNCTION BODY BELOW#
+ . /dev/fd/4
#fn AFTER _fn_init .dot SOURCES IT#
fn() { echo "this would be command 1"
echo "$common_param"
} 4<<-REQ 5<<-\RESET
: ${_if_unset?shell will ERR and print this to stderr}
: ${common_param="REQ/RESET added to all funcs"}
REQ
_fn_init 'fn' \
'echo "this would be command 1"' \
'echo "$common_param"'
RESET
GEREKLİDİR
Bu işlevi çağırmak istersem, ortam değişkeni _if_unset
ayarlanmadıkça ölecektir .
fn
#OUTPUT#
+ fn
/dev/fd/4: line 1: _if_unset: shell will ERR and print this to stderr
Lütfen kabuk izlerinin sırasına dikkat edin - sadece ayarlanmadığında fn
çağrıldığında başarısız olmaz _if_unset
, aynı zamanda asla ilk sırada çalışmaz . Bu belge genişlemeleriyle çalışırken anlaşılması gereken en önemli faktör budur - her zaman önce gerçekleşmelidir çünkü <<input
sonuçta oldukları gibi .
Hata /dev/fd/4
, üst kabuk işleve teslim edilmeden önce bu girdiyi değerlendirdiği için gelir . Gerekli ortamı test etmenin en basit, en etkili yoludur.
Her neyse, arıza kolayca giderilebilir.
_if_unset=set fn
#OUTPUT#
+ _if_unset=set
+ fn
+ echo 'this would be command 1'
this would be command 1
+ echo 'REQ/RESET added to all funcs'
REQ/RESET added to all funcs
ESNEK
Değişken common_param
, tarafından bildirilen her işlev için girişte varsayılan bir değer olarak değerlendirilir _fn_init
. Ancak bu değer, benzer şekilde beyan edilen her fonksiyon tarafından da onurlandırılacak olan diğer değerlerle de değiştirilebilir. Şimdi kabuk izlerini bırakacağım - burada herhangi bir haritaya girmeyeceğiz.
set +vx
_fn_init 'fn' \
'echo "Hi! I am the first function."' \
'echo "$common_param"'
_fn_init 'fn2' \
'echo "This is another function."' \
'echo "$common_param"'
_if_unset=set ;
Yukarıda iki işlevi beyan edip ayarladım _if_unset
. Şimdi, herhangi bir işlevi çağırmadan önce, common_param
onları aradığımda kendileri ayarlayacaklarını görebilmeniz için ayarlayacağım.
unset common_param ; echo
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
REQ/RESET added to all funcs
This is another function.
REQ/RESET added to all funcs
Ve şimdi arayanın kapsamından:
echo $common_param
#OUTPUT#
REQ/RESET added to all funcs
Ama şimdi tamamen başka bir şey olmasını istiyorum:
common_param="Our common parameter is now something else entirely."
fn ; echo
fn2 ; echo
#OUTPUT#
Hi! I am the first function.
Our common parameter is now something else entirely.
This is another function.
Our common parameter is now something else entirely.
Ve eğer ayarlamazsam _if_unset
?
unset _if_unset ; echo
echo "fn:"
fn ; echo
echo "fn2:"
fn2 ; echo
#OUTPUT#
fn:
dash: 1: _if_unset: shell will ERR and print this to stderr
fn2:
dash: 1: _if_unset: shell will ERR and print this to stderr
SIFIRLA
Herhangi bir zamanda işlevin durumunu sıfırlamanız gerekirse, kolayca yapılabilir. Sadece yapmanız gerekir (fonksiyonun içinden):
. /dev/fd/5
Başlangıçta 5<<\RESET
girdi dosya tanımlayıcısında işlevi bildirmek için kullanılan bağımsız değişkenleri kaydettim . Öyleyse .dot
, kabukta herhangi bir zamanda kaynak yapmak, onu ilk etapta oluşturan süreci tekrarlayacaktır. POSIX'in dosya tanımlayıcı cihaz düğümü yollarını (kabuklar için bir gerekliliktir .dot
) gerçekten belirtmediğini görmezden gelmek istiyorsanız, oldukça kolay, gerçekten ve tamamen taşınabilir .
Bu davranışı kolayca genişletebilir ve işleviniz için farklı durumlar yapılandırabilirsiniz.
DAHA?
Bu arada yüzeyi zar zor çizer. Bu teknikleri genellikle herhangi bir zamanda beyan edilebilir küçük yardımcı işlevleri bir ana işlevin girişine yerleştirmek için kullanırım - örneğin, ek konumlandırma için$@
gerektiğinde diziler için. Aslında - inandığım gibi, üst düzey mermilerin zaten yapması buna çok yakın bir şey olmalı. Programlı olarak çok kolay adlandırıldıklarını görebilirsiniz.
Ya da bir in-line fonksiyonu - - aynı zamanda gibi parametrenin sınırlı tür kabul eder ve daha sonra bir lambda çizgisinde bir tek kullanımlık ya da başka kapsamı sınırlı brülör-fonksiyonu tanımlayan bir jeneratör işlevi bildirmek için sadece bu unset -f
'kendini zaman s vasıtasıyla. Sen bir kabuk işlevi etrafta geçebilir.