Not
bash
Etiketi nedeniyle ağır Bash odaklı bir cevap veriyorum .
Kısa cevap
Bash'de yalnızca adlandırılmış değişkenlerle uğraştığınız sürece, bu işlev boş bir dizi olsa bile değişkenin ayarlanmış olup olmadığını her zaman size bildirmelidir.
variable-is-set() {
declare -p "$1" &>/dev/null
}
Bu neden çalışıyor?
Bash'te (en azından 3.0'a kadar), var
bildirilen / ayarlanan bir değişkense, geçerli türü ve değeri ne olursa olsun değişkeni ayarlayacak declare -p var
bir declare
komut verir var
ve durum kodu 0
(başarı) döndürür . Eğer var
bildirilmeyen, o zaman declare -p var
bir hata mesajı verir stderr
ve getiri durum kodu 1
. Kullanılması &>/dev/null
, hem normal yönlendirir stdout
ve stderr
çıktı /dev/null
, görülecek asla ve durum kodu değiştirmeden. Böylece işlev yalnızca durum kodunu döndürür.
Bash'de neden diğer yöntemler (bazen) başarısız oluyor?
[ -n "$var" ]
: Bu sadece ${var[0]}
boş olup olmadığını kontrol eder . (Bash'te $var
aynıdır ${var[0]}
.)
[ -n "${var+x}" ]
: Bu yalnızca ${var[0]}
ayarlı olup olmadığını kontrol eder .
[ "${#var[@]}" != 0 ]
: Bu yalnızca en az bir dizinin $var
ayarlanıp ayarlanmadığını kontrol eder .
Bu yöntem Bash'te başarısız olduğunda
Bu yalnızca (dahil adında değişkenler için çalışır $_
) değil, bazı özel değişkenler ( $!
, $@
, $#
, $$
, $*
, $?
, $-
, $0
, $1
, $2
, ..., ve herhangi ben unutmuş olabilir). Bunların hiçbiri diziler olmadığından, POSIX stili [ -n "${var+x}" ]
tüm bu özel değişkenler için çalışır. Ancak, birçok özel değişken, işlevler çağrıldığında değerleri / varlığı değiştirdiği için bir işleve sarmaya dikkat edin.
Kabuk uyumluluk notu
Komut dosyanız diziler içeriyorsa ve mümkün olduğunca çok sayıda kabukla uyumlu hale getirmeye çalışıyorsanız, typeset -p
bunun yerine kullanmayı düşünün declare -p
. Ksh'ın sadece eskisini desteklediğini okudum, ancak bunu test edemedim. Bash 3.0+ ve Zsh 5.5.1'in her ikisini de desteklediğini typeset -p
ve declare -p
sadece hangisinin diğeri için alternatif olduğu konusunda farklı olduğunu biliyorum . Ancak bu iki anahtar kelimenin ötesindeki farklılıkları test etmedim ve başka kabukları da test etmedim.
Komut dosyanızın POSIX sh uyumlu olması gerekiyorsa dizileri kullanamazsınız. Diziler olmadan [ -n "{$var+x}" ]
çalışır.
Bash'te farklı yöntemler için karşılaştırma kodu
Bu fonksiyon, unsets değişken var
, eval
geçti kod s olmadığını belirlemek için testler çalışan var
tarafından ayarlanır eval
d kodu ve son olarak, farklı testler için elde edilen durum kodlarını göstermektedir.
I atlama ediyorum test -v var
, [ -v var ]
ve [[ -v var ]]
bunlar POSIX standardına aynı sonuçlar için [ -n "${var+x}" ]
, Bash 4.2+ gerektirirken. Ayrıca atlıyorum typeset -p
çünkü declare -p
test ettiğim kabuklardakiyle aynı (Bash 3.0 - 5.0 ve Zsh 5.5.1).
is-var-set-after() {
# Set var by passed expression.
unset var
eval "$1"
# Run the tests, in increasing order of accuracy.
[ -n "$var" ] # (index 0 of) var is nonempty
nonempty=$?
[ -n "${var+x}" ] # (index 0 of) var is set, maybe empty
plus=$?
[ "${#var[@]}" != 0 ] # var has at least one index set, maybe empty
count=$?
declare -p var &>/dev/null # var has been declared (any type)
declared=$?
# Show test results.
printf '%30s: %2s %2s %2s %2s\n' "$1" $nonempty $plus $count $declared
}
Test senaryosu kodu
Değişken ilişkilendirilebilir bir dizi olarak bildirilmemişse, sayısal olmayan dizi indekslerinin Bash tarafından "0" olarak işlenmesi nedeniyle test sonuçlarının beklenmedik olabileceğini unutmayın. Ayrıca, ilişkilendirilebilir diziler yalnızca Bash 4.0+ için geçerlidir.
# Header.
printf '%30s: %2s %2s %2s %2s\n' "test" '-n' '+x' '#@' '-p'
# First 5 tests: Equivalent to setting 'var=foo' because index 0 of an
# indexed array is also the nonindexed value, and non-numerical
# indices in an array not declared as associative are the same as
# index 0.
is-var-set-after "var=foo" # 0 0 0 0
is-var-set-after "var=(foo)" # 0 0 0 0
is-var-set-after "var=([0]=foo)" # 0 0 0 0
is-var-set-after "var=([x]=foo)" # 0 0 0 0
is-var-set-after "var=([y]=bar [x]=foo)" # 0 0 0 0
# '[ -n "$var" ]' fails when var is empty.
is-var-set-after "var=''" # 1 0 0 0
is-var-set-after "var=([0]='')" # 1 0 0 0
# Indices other than 0 are not detected by '[ -n "$var" ]' or by
# '[ -n "${var+x}" ]'.
is-var-set-after "var=([1]='')" # 1 1 0 0
is-var-set-after "var=([1]=foo)" # 1 1 0 0
is-var-set-after "declare -A var; var=([x]=foo)" # 1 1 0 0
# Empty arrays are only detected by 'declare -p'.
is-var-set-after "var=()" # 1 1 1 0
is-var-set-after "declare -a var" # 1 1 1 0
is-var-set-after "declare -A var" # 1 1 1 0
# If 'var' is unset, then it even fails the 'declare -p var' test.
is-var-set-after "unset var" # 1 1 1 1
Test çıktısı
Başlık satırı tekabül test Simgesellerine [ -n "$var" ]
, [ -n "${var+x}" ]
, [ "${#var[@]}" != 0 ]
ve declare -p var
sırasıyla.
test: -n +x #@ -p
var=foo: 0 0 0 0
var=(foo): 0 0 0 0
var=([0]=foo): 0 0 0 0
var=([x]=foo): 0 0 0 0
var=([y]=bar [x]=foo): 0 0 0 0
var='': 1 0 0 0
var=([0]=''): 1 0 0 0
var=([1]=''): 1 1 0 0
var=([1]=foo): 1 1 0 0
declare -A var; var=([x]=foo): 1 1 0 0
var=(): 1 1 1 0
declare -a var: 1 1 1 0
declare -A var: 1 1 1 0
unset var: 1 1 1 1
özet
declare -p var &>/dev/null
(% 100?) en az 3.0'dan beri Bash'te adlandırılmış değişkenleri test etmek için güvenilirdir.
[ -n "${var+x}" ]
POSIX uyumlu durumlarda güvenilirdir, ancak dizileri işleyemez.
- Bir değişkenin boş olup olmadığını ve diğer kabuklarda bildirilen değişkenleri kontrol etmek için başka testler de mevcuttur. Ancak bu testler ne Bash ne de POSIX komut dosyaları için uygun değildir.
if test $# -gt 0; then printf 'arg <%s>\n' "$@"; fi
.