שאלה בדוק אם המערך ריק ב- Bash


יש לי מערך אשר מקבל מלא הודעות שגיאה שונות כמו הסקריפט שלי פועל.

אני צריך דרך לבדוק אם הוא ריק של לא בסוף התסריט ולנקוט פעולה ספציפית אם זה.

כבר ניסיתי לטפל בו כמו VAR רגיל באמצעות -z כדי לבדוק את זה, אבל זה לא נראה לעבוד. האם יש דרך לבדוק אם מערך ריק או לא בבש?

תודה


82
2018-02-11 03:59






תשובות:


נניח את המערך שלך $errors, רק לבדוק אם ספירת האלמנטים היא אפס.

if [ ${#errors[@]} -eq 0 ]; then
    echo "No errors, hooray"
else
    echo "Oops, something went wrong..."
fi

113
2018-02-11 04:10



שים לב ש = הוא מפעיל מחרוזת. זה קורה לעבוד בסדר במקרה זה, אבל הייתי משתמש מפעיל את החשבון הנכון -eq במקום (רק למקרה שהייתי רוצה לעבור -ge או -lt, וכו.). - musiphil
לא עובד עם set -u: "משתנה לא מכוון" - אם המערך ריק. - Igor
@Igor: עובד בשבילי בבש 4.4. set -u;  foo=();  [ ${#foo[@]} -eq 0 ] && echo empty. אם אני unset foo, ואז הוא מדפיס foo: unbound variable, אבל זה שונה: משתנה המערך אינו קיים כלל, ולא קיים וריק. - Peter Cordes
נבדק גם באש 3.2 (OSX) בעת שימוש set -u - כל עוד אתה מכריז על המשתנה הראשון שלך, זה עובד בצורה מושלמת. - zeroimpl


ניתן גם לשקול את המערך כמשתנה פשוט. בדרך זו, רק באמצעות

if [ -z "$array" ]; then
    echo "Array empty"
else
    echo "Array non empty"
fi

או באמצעות הצד השני

if [ -n "$array" ]; then
    echo "Array non empty"
else
    echo "Array empty"
fi

הבעיה עם פתרון זה היא שאם מערך הוא הכריז כך: array=('' foo). בדיקות אלו ידווחו על המערך כריק, בעוד שברור שלא. (תודה @musiphil!)

שימוש [ -z "$array[@]" ] הוא בבירור לא פתרון לא. לא ציון סוגריים מסולסלים מנסה לפרש $array כמחרוזת ([@] הוא במקרה זה מחרוזת מילולית פשוטה), ולכן הוא תמיד דיווח כעל שקר: "הוא המיתר המילולי [@] ריק? "ברור שלא.


6
2018-06-23 10:29



[ -z "$array" ] או [ -n "$array" ] לא עובד. נסה array=('' foo); [ -z "$array" ] && echo empty, והוא יודפס empty למרות ש array הוא בבירור לא ריק. - musiphil
[[ -n "${array[*]}" ]] interpolates את המערך כולו כמחרוזת, אשר אתה בודק אורך שאינו אפס. אם אתה מחשיב array=("" "") להיות ריק, במקום שיש שני אלמנטים ריקים, זה עשוי להיות שימושי. - Peter Cordes


בדרך כלל אני משתמש בהרחבה אריתמטית במקרה זה:

if (( ${#a[@]} )); then
    echo not empty
fi

3
2017-08-02 06:04



נחמד ונקי! אני אוהב את זה. אני גם לציין כי אם האלמנט הראשון של המערך הוא תמיד nonempty, (( ${#a} )) (אורך האלמנט הראשון) יעבוד גם. עם זאת, זה ייכשל a=(''), ואילו (( ${#a[@]} )) הנתון בתשובה יצליח. - cxw


בדקתי את זה bash-4.4.0You

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]} ]]; then
        echo not empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

ו bash-4.1.5You

#!/usr/bin/env bash
set -eu
check() {
    if [[ ${array[@]:+${array[@]}} ]]; then
        echo non-empty
    else
        echo empty
    fi
}
check   # empty
array=(a b c d)
check   # not empty
array=()
check   # empty

במקרה האחרון אתה צריך את המבנה הבא:

${array[@]:+${array[@]}}

עבור זה לא להיכשל על מערך ריק או unset. ללא שם: זהו אם אתה עושה set -eu כמו שאני עושה בדרך כלל. זה מספק לבדיקות שגיאה מחמירות יותר. מ את המסמכיםYou

צא מיד אם צינור (ראה צינורות), אשר עשוי להיות מורכב פקודה אחת פשוטה (ראה פקודות פשוטות), רשימה (ראה רשימות), או פקודה מורכבת (ראה פקודות Compound) מחזירה מצב לא אפס. פגז אינו יוצא אם הפקודה שנכשלת היא חלק מרשימת הפקודות מיד לאחר זמן מה או עד מילת המפתח, חלק מהבדיקה בהצהרה אם, חלק מכל פקודה שבוצעה ב & | רשימה למעט הפקודה הבאה Final & & | |, כל פקודה בצינור אבל האחרון, או אם המצב של הפקודה לחזור להיות הפוך עם !. אם פקודה מורכבת שאינה subshell מחזירה סטטוס שאינו אפס מכיוון שפקודה נכשלה בזמן שהתעלמת, הקליפה אינה יוצאת. מלכודת על ERR, אם מוגדר, מבוצע לפני פגז יוצא.

אפשרות זו חלה על סביבת המעטפת ועל כל סביבת subshell בנפרד (ראה ביצוע פקודת סביבה), ועשויה לגרום להופעת תת-יחידות לפני ביצוע כל הפקודות שבתת-המערכת.

אם פקודה מורכבת או פונקציית פגז מבוצעת בהקשר שבו מתעלמים, אף אחת מהפקודות המבוצעות בתוך פקודת המתחם או גוף הפונקציה לא תושפע מההגדרה -e, גם אם -e מוגדרת ופקודה מחזירה מצב כשל. אם פקודה מורכבת או פונקציית פגז מגדירה -e בעת ביצוע בהקשר שבו הוא מתעלם, הגדרה זו לא תהיה כל השפעה עד פקודה מורכבת או פקודה המכילה את השיחה לפונקציה משלים.

-u

התייחס אל משתנים ופרמטרים שונים שאינם פרמטרים מיוחדים '@' או '*' כשגיאה בעת ביצוע הרחבת פרמטרים. הודעת שגיאה תירשם לשגיאה הרגילה, ופגז שאינו אינטראקטיבי ייסגר.

אם אתה לא צריך את זה, אתה מוזמן להשמיט :+${array[@]} חלק.

כמו כן, שים לב, כי זה חיוני לשימוש [[ מפעיל כאן, עם [ אתה מקבל:

$ cat 1.sh
#!/usr/bin/env bash
set -eu
array=(a b c d)
if [ "${array[@]}" ]; then
    echo non-empty
else
    echo empty
fi

$ ./1.sh
_/1.sh: line 4: [: too many arguments
empty

2
2017-12-04 14:58



עם -u אתה צריך להשתמש בפועל ${array[@]+"${array[@]}"} cf stackoverflow.com/a/34361807/1237617 - Jakub Bochenski
@JakubBochenski איזו גרסה של באש אתה מדבר? gist.github.com/x-yuri/d933972a2f1c42a49fc7999b8d5c50b9 - x-yuri
הבעיה בדוגמה אחת בסוגריים היא @, בוודאי. אתה יכול להשתמש * הרחבת מערך כמו [ "${array[*]}" ], לא? ובכל זאת, [[ עובד גם בסדר. ההתנהגות של שני אלה עבור מערך עם מחרוזות ריקות מרובים הוא קצת מפתיע. שניהם [ ${#array[*]} ] ו [[ "${array[@]}" ]] הם שקר עבור array=() ו array=('') אבל נכון array=('' '') (שתי מחרוזות ריקות או יותר). אם אתה רוצה אחד או יותר מחרוזות ריקות לכל לתת אמת, אתה יכול להשתמש [ ${#array[@]} -gt 0 ]. אם אתה רוצה את כולם שקר, אתה יכול אולי // הם החוצה. - eisd
@eisd אני יכול להשתמש [ "${array[*]}" ], אבל אם הייתי נתקל בביטוי כזה, יהיה לי קשה יותר להבין מה הוא עושה. מאז [...] פועלת במונחים של מיתרים על התוצאה של אינטרפולציה. לעומת זאת [[...]], אשר יכול להיות מודע מה interpolated. כלומר, הוא יכול לדעת שזה עבר מערך. [[ ${array[@]} ]] קורא לי "לבדוק אם המערך הוא לא ריק", בעוד [ "${array[*]}" ] כמו "לבדוק אם התוצאה של אינטרפולציה של כל האלמנטים מערך הוא מחרוזת לא ריקה". - x-yuri
... באשר להתנהגות עם שני מיתרים ריקים זה בכלל לא מפתיע אותי. מה שמפתיע הוא ההתנהגות עם מחרוזת ריקה אחת. אבל סביר להניח. לגבי [ ${#array[*]} ], כנראה התכוונת [ "${array[*]}" ], שכן הראשון הוא נכון עבור כל מספר של גורמים. מכיוון שמספר האלמנטים הוא תמיד מחרוזת שאינה ריקה. לגבי השני עם שני אלמנטים, הביטוי בתוך סוגריים מתרחב ל ' ' שהוא מחרוזת שאינה ריקה. בנוגע ל [[ ${array[@]} ]], הם פשוט חושבים (ובצדק) כי כל מערך של שני אלמנטים הוא לא ריק. - x-yuri


במקרה שלי, תשובה שנייה לא היה מספיק כי יכול להיות שיש לבן. באתי עם:

if [ "$(echo -ne ${opts} | wc -m)" -eq 0 ]; then
  echo "No options"
else
  echo "Options found"
fi

0
2018-02-17 19:54



echo | wc נראה חסר תועלת ללא צורך בהשוואה פגז מובנה. - Peter Cordes
לא בטוח אם אני מבין @ PeterCordes, אני יכול לשנות את התשובות השני " [ ${#errors[@]} -eq 0 ]; בדרך לעקוף את הבעיה שטח לבן? אני מעדיף גם את המובנה. - Micha
איך בדיוק עושה רווח לבן בעיה? $# מתרחב למספר, ועובד מצוין גם לאחר opts+=(""). למשל unset opts;  opts+=("");opts+=(" "); echo "${#opts[@]}" ואני מקבל 2. האם תוכל להציג דוגמה למשהו שאינו פועל? - Peter Cordes
זה מזמן. IIRC מקור המקור תמיד מודפס לפחות "". לכן, עבור opts = "" או opts = ("") אני צריך 0, לא 1, תוך התעלמות newline ריק או מחרוזת ריקה. - Micha
בסדר, אז אתה צריך לטפל opts=("") כמו opts=()? זה לא מערך ריק, אבל אתה יכול לבדוק מערך ריק או אלמנט ראשון ריק עם opts=("");  [[ "${#opts[@]}" -eq 0 || -z "$opts" ]] && echo empty. שים לב שהתשובה הנוכחית שלך אומרת "אין אפשרויות" עבור opts=("" "-foo"), שהוא מזויף לחלוטין, וזה משחזר את ההתנהגות. אתה יכול [[ -z "${opts[*]}" ]] אני מניח, כדי interpolate כל האלמנטים מערך לתוך מחרוזת שטוחה, אשר -z בודק אורך שאינו אפס.  אם בדיקת האלמנט הראשון מספיקה, -z "$opts" עובד. - Peter Cordes


אני מעדיף להשתמש בסוגריים כפולים:

if [[ !${array[@]} ]]
then
    echo "Array is empty"
else
    echo "Array is not empty"
fi

סוגריים כפולים: https://stackoverflow.com/questions/669452/is-preferable-over-in-bash


0
2017-11-04 06:40