it-swarm.asia

اختبار لسلسلة طول غير صفرية في Bash: [-n "$ var"] أو ["$ var"]

رأيت البرامج النصية 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
146
AllenHalsey

تحرير: هذا هو الإصدار الأكثر اكتمالا الذي يظهر المزيد من الاختلافات بين[((ويعرف أيضا باسم 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

إذا كنت تريد معرفة ما إذا كان المتغير بطول غير صفري ، فقم بأي مما يلي:

  • اقتباس المتغير بين قوسين (العمود 2 أ)
  • استخدم -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
343
Dennis Williamson

من الأفضل استخدام أقوى[[ فيما يتعلق بـ 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

الوظائف ذات الصلة والوثائق

هناك الكثير من المشاركات المتعلقة بهذا الموضوع. وهنا عدد قليل:

11
codeforester

وهنا بعض الاختبارات أكثر

صحيح إذا كانت السلسلة غير فارغة:

[ -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"
8
Steven Penny

استخدم case/esac للاختبار

case "$var" in
  "") echo "zero length";;
esac
1
ghostdog74

الجواب الصحيح هو ما يلي:

if [[ -n $var ]] ; then
  blah
fi

لاحظ استخدام [[...]] ، والذي يعالج بشكل صحيح اقتباس المتغيرات من أجلك.

0
user2592126

طريقة بديلة وربما أكثر شفافية لتقييم متغير env فارغ هو استخدام ...

  if [ "x$ENV_VARIABLE" != "x" ] ; then
      echo 'ENV_VARIABLE contains something'
  fi
0
user1310789