رأيت البرامج النصية bash اختبار لسلسلة طول غير صفرية بطريقتين مختلفتين. تستخدم معظم البرامج النصية الخيار -n:
#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
# Do something when var is non-zero length
fi
لكن الخيار -n غير مطلوب فعلاً:
# Without the -n option
if [ "$var" ]; then
# Do something when var is non-zero length
fi
ما هي الطريقة الأفضل؟
وبالمثل ، هذه هي الطريقة الأفضل لاختبار الطول الصفري:
if [ -z "$var" ]; then
# Do something when var is zero-length
fi
أو
if [ ! "$var" ]; then
# Do something when var is zero-length
fi
تحرير: هذا هو الإصدار الأكثر اكتمالا الذي يظهر المزيد من الاختلافات بين[
((ويعرف أيضا باسم test
) و[[
.
يوضح الجدول التالي ما إذا كان المتغير مقتبسًا أم لا ، وما إذا كنت تستخدم أقواس مفردة أو مزدوجة وما إذا كان المتغير يحتوي فقط على مساحة ، هي الأشياء التي تؤثر على ما إذا كان استخدام اختبار مع أو بدون -n/-z
مناسبًا للتحقق من متغير.
1a 2a 3a 4a 5a 6a |1b 2b 3b 4b 5b 6b
[ [" [-n [-n" [-z [-z" |[[ [[" [[-n [[-n" [[-z [[-z"
unset: false false true false true true |false false false false true true
null : false false true false true true |false false false false true true
space: false true true true true false |true true true true false false
zero : true true true true false false |true true true true false false
digit: true true true true false false |true true true true false false
char : true true true true false false |true true true true false false
hyphn: true true true true false false |true true true true false false
two : -err- true -err- true -err- false |true true true true false false
part : -err- true -err- true -err- false |true true true true false false
Tstr : true true -err- true -err- false |true true true true false false
Fsym : false true -err- true -err- false |true true true true false false
T= : true true -err- true -err- false |true true true true false false
F= : false true -err- true -err- false |true true true true false false
T!= : true true -err- true -err- false |true true true true false false
F!= : false true -err- true -err- false |true true true true false false
Teq : true true -err- true -err- false |true true true true false false
Feq : false true -err- true -err- false |true true true true false false
Tne : true true -err- true -err- false |true true true true false false
Fne : false true -err- true -err- false |true true true true false false
إذا كنت تريد معرفة ما إذا كان المتغير بطول غير صفري ، فقم بأي مما يلي:
-n
واقتبس المتغير بين قوسين (العمود 4 أ)-n
(الأعمدة 1 ب - 4 ب)لاحظ في العمود 1 أ بدءًا من الصف المسمى "اثنين" أن النتيجة تشير إلى أن [
تقوم بتقييم المحتويات للمتغير كما لو كانت جزءًا من التعبير الشرطي (النتيجة تطابق التأكيد المضمّن من قبل " T "أو" F "في عمود الوصف). عند استخدام [[
(العمود 1 ب) ، يُنظر إلى المحتوى المتغير كسلسلة ولا يتم تقييمه.
تنتج الأخطاء في العمودين 3 أ و 5 أ عن حقيقة أن القيمة المتغيرة تتضمن مسافة وأن المتغير غير مذكور. مرة أخرى ، كما هو موضح في العمودين 3 ب و 5 ب ، يقيم [[
محتويات المتغير كسلسلة.
إذا كنت تستخدم [
، فإن المفتاح للتأكد من عدم حصولك على نتائج غير متوقعة هو اقتباس المتغير. باستخدام [[
، لا يهم.
رسائل الخطأ ، التي يتم قمعها ، هي "توقع مشغل واحد" أو "مشغل ثنائي متوقع".
هذا هو السيناريو الذي أنتج الجدول أعلاه.
#!/bin/bash
# by Dennis Williamson
# 2010-10-06, revised 2010-11-10
# for http://stackoverflow.com/questions/3869072/test-for-non-zero-length-string-in-bash-n-var-or-var
# designed to fit an 80 character terminal
dw=5 # description column width
w=6 # table column width
t () { printf "%-${w}s" "true"; }
f () { [[ $? == 1 ]] && printf "%-${w}s" "false " || printf "%-${w}s" "-err- "; }
o=/dev/null
echo ' 1a 2a 3a 4a 5a 6a |1b 2b 3b 4b 5b 6b'
echo ' [ [" [-n [-n" [-z [-z" |[[ [[" [[-n [[-n" [[-z [[-z"'
while read -r d t
do
printf "%-${dw}s: " "$d"
case $d in
unset) unset t ;;
space) t=' ' ;;
esac
[ $t ] 2>$o && t || f
[ "$t" ] && t || f
[ -n $t ] 2>$o && t || f
[ -n "$t" ] && t || f
[ -z $t ] 2>$o && t || f
[ -z "$t" ] && t || f
echo -n "|"
[[ $t ]] && t || f
[[ "$t" ]] && t || f
[[ -n $t ]] && t || f
[[ -n "$t" ]] && t || f
[[ -z $t ]] && t || f
[[ -z "$t" ]] && t || f
echo
done <<'EOF'
unset
null
space
zero 0
digit 1
char c
hyphn -z
two a b
part a -a
Tstr -n a
Fsym -h .
T= 1 = 1
F= 1 = 2
T!= 1 != 2
F!= 1 != 1
Teq 1 -eq 1
Feq 1 -eq 2
Tne 1 -ne 2
Fne 1 -ne 1
EOF
من الأفضل استخدام أقوى[[
فيما يتعلق بـ Bash.
if [[ $var ]]; then # var is set and it is not empty
if [[ ! $var ]]; then # var is not set or it is set to an empty string
بنائين أعلاه تبدو نظيفة وقابلة للقراءة. يجب أن تكون كافية في معظم الحالات.
لاحظ أننا لسنا بحاجة إلى اقتباس التوسعات المتغيرة داخل [[
لأنه لا يوجد خطر من تقسيم الكلمات و التهامس .
لمنع shellcheck الشكاوى الطفيفة حول [[ $var ]]
و [[ ! $var ]]
، يمكننا استخدام الخيار -n
.
في حالة نادرة الاضطرار إلى التمييز بين "التعيين إلى سلسلة فارغة" مقابل "عدم التعيين على الإطلاق" ، يمكننا استخدام هذه:
if [[ ${var+x} ]]; then # var is set but it could be empty
if [[ ! ${var+x} ]]; then # var is not set
if [[ ${var+x} && ! $var ]]; then # var is set and is empty
يمكننا أيضًا استخدام اختبار -v
:
if [[ -v var ]]; then # var is set but it could be empty
if [[ ! -v var ]]; then # var is not set
if [[ -v var && ! $var ]]; then # var is set and is empty
if [[ -v var && -z $var ]]; then # var is set and is empty
هناك الكثير من المشاركات المتعلقة بهذا الموضوع. وهنا عدد قليل:
[[
vs [
[
vs [[
وهنا بعض الاختبارات أكثر
صحيح إذا كانت السلسلة غير فارغة:
[ -n "$var" ]
[[ -n $var ]]
test -n "$var"
[ "$var" ]
[[ $var ]]
(( ${#var} ))
let ${#var}
test "$var"
صحيح إذا كانت السلسلة فارغة:
[ -z "$var" ]
[[ -z $var ]]
test -z "$var"
! [ "$var" ]
! [[ $var ]]
! (( ${#var} ))
! let ${#var}
! test "$var"
استخدم case/esac
للاختبار
case "$var" in
"") echo "zero length";;
esac
الجواب الصحيح هو ما يلي:
if [[ -n $var ]] ; then
blah
fi
لاحظ استخدام [[...]]
، والذي يعالج بشكل صحيح اقتباس المتغيرات من أجلك.
طريقة بديلة وربما أكثر شفافية لتقييم متغير env فارغ هو استخدام ...
if [ "x$ENV_VARIABLE" != "x" ] ; then
echo 'ENV_VARIABLE contains something'
fi