วิธีการทดสอบว่าองค์ประกอบอาร์เรย์มีความเท่าเทียมกันในการทุบตี?


15

อาร์เรย์ต่อไปนี้แสดงจำนวนดิสก์ในเครื่อง linux แต่ละเครื่อง

แต่ละอาร์เรย์เดียวรวมถึงจำนวนของดิสก์ในที่เครื่องลินุกซ์

echo ${ARRAY_DISK_Quantity[*]}
4 4 4 4 2 4 4 4

วิธีง่ายๆในการระบุว่าทุกค่าของอาร์เรย์มีค่าเท่ากัน?

สถานะที่ดี:

4 4 4 4 4 4 4 4

สถานะไม่ดี:

4 4 4 4 4 4 2 4

สถานะไม่ดี:

6 6 6 6 6 6 6 6 6 6 2 6 2

คำตอบมากมายและไม่มีคะแนน?
jesse_b

นี่จะเป็นการทดสอบเลขจำนวนเต็มหรือควรทดสอบสตริงด้วยหรือไม่
jesse_b

ฉันแค่รอคำตอบที่ดีที่สุดไม่ต้องกังวลเร็ว ๆ นี้ฉันจะลงคะแนน
yael

ฉันหมายถึงคนอื่น คำถามนี้สมควรได้รับการโหวต IMO
jesse_b

เมื่อคุณต้องการบางสิ่งบางอย่างอย่างน้อยระดับความซับซ้อนนี้เป็นเวลาที่ดีในการเริ่มใช้ภาษาการเขียนโปรแกรมจริงจนกว่าจะสายเกินไป ...
ชื่อที่แสดง

คำตอบ:


11

bash+ GNU sort+ grepโซลูชันGNU :

if [ "${#array[@]}" -gt 0 ] && [ $(printf "%s\000" "${array[@]}" | 
       LC_ALL=C sort -z -u |
       grep -z -c .) -eq 1 ] ; then
  echo ok
else
  echo bad
fi

คำอธิบายภาษาอังกฤษ: หากการเรียงลำดับที่ไม่ซ้ำกันขององค์ประกอบของอาร์เรย์ส่งผลให้มีเพียงองค์ประกอบเดียวแล้วพิมพ์ "ok" มิฉะนั้นพิมพ์ "ไม่ดี"

อาร์เรย์จะพิมพ์ด้วย NUL ไบต์แยกแต่ละองค์ประกอบประปาเข้า GNU sort (อาศัย-zหรือที่รู้จัก--zero-terminatedและ-uaka --uniqueตัวเลือก) แล้วเข้าgrep(โดยใช้ตัวเลือก-zที่รู้จัก--null-dataและ-caka --count) ในการนับเส้นเอาท์พุท

ต่างจากรุ่นก่อนหน้าของฉันฉันไม่สามารถใช้wcที่นี่ได้เพราะต้องการบรรทัดอินพุตที่ถูกยกเลิกด้วยการขึ้นบรรทัดใหม่ ... และใช้sedหรือtrแปลงsortNUL ให้เป็นบรรทัดใหม่หลังจากที่จะเอาชนะจุดประสงค์ของการใช้ตัวคั่น NUL grep -cทำให้ทดแทนที่เหมาะสม


นี่คือสิ่งเดียวกับที่เขียนใหม่ในฟังก์ชั่น:

function count_unique() {
  local LC_ALL=C

  if [ "$#" -eq 0 ] ; then 
    echo 0
  else
    echo "$(printf "%s\000" "$@" |
              sort --zero-terminated --unique |
              grep --null-data --count .)"
  fi
}



ARRAY_DISK_Quantity=(4 4 4 4 2 4 4 4)

if [ "$(count_unique "${ARRAY_DISK_Quantity[@]}")" -eq 1 ] ; then
  echo "ok"
else
  echo "bad"
fi

1
โปรดทราบว่าsort -uจะไม่ส่งคืนองค์ประกอบที่ไม่ซ้ำ แต่อย่างใดอย่างหนึ่งขององค์ประกอบแต่ละชุดที่เรียงลำดับเดียวกัน ตัวอย่างเช่นมันจะพูดว่า "ok" บนARRAY_DISK_Quantity=(① ②)ระบบ GNU โดยที่โลแคลจะตัดสินใจว่าอักขระ 2 ตัวเหล่านั้นเรียงกันเหมือนกัน คุณต้องการLC_ALL=C sort -uความเป็นเอกลักษณ์แบบไบต์ต่อไบต์
Stéphane Chazelas

เพียงบันทึกอื่นมันจะล้มเหลวเช่นกันในกรณีที่ไม่มีดิสก์เพิ่มเติมปรากฏขึ้นจาก CLI ดังนั้นจำเป็นต้องเพิ่มไวยากรณ์นี้ด้วย
yael

[[`printf"% s \ n "" $ {ARRAY_DISK_Quantity [@]} "| wc -l `-eq` printf "% s \ n" "$ {ARRAY_DISK_Quantity [@]}" | grep -c "0" `]] && echo ล้มเหลว
yael

@ StéphaneChazelasปัญหา locale นั้นคุ้มค่าที่จะจัดการเช่นเดียวกับปัญหาของ IFS การทดสอบรายการว่างคือ IMO ทำได้ดีที่สุดแยกกัน - ไม่จำเป็นต้องตรวจสอบองค์ประกอบที่ไม่ซ้ำกันในชุดที่ว่างเปล่า
cas

สวัสดี Cas ฉันชอบคำตอบก่อนหน้าของคุณ
yael

8

ด้วยzsh:

if ((${#${(u)ARRAY_DISK_Quantity[@]}} == 1)); then
  echo OK
else
  echo not OK
fi

(u)ตำแหน่งการขยายพารามิเตอร์อยู่ที่ไหนเพื่อขยายค่าที่ไม่ซ้ำ ดังนั้นเราจะได้รับการนับค่าที่ไม่ซ้ำกันในอาร์เรย์

แทนที่== 1ด้วย<= 1คือคุณต้องการพิจารณาอาร์เรย์ว่างเปล่าเป็น OK

ด้วยksh93คุณสามารถเรียงลำดับอาร์เรย์และตรวจสอบว่าองค์ประกอบแรกเหมือนกันกับครั้งสุดท้าย:

set -s -- "${ARRAY_DISK_Quantity[@]}"
if [ "$1" = "${@: -1}" ]; then
  echo OK
else
  echo not OK
fi

ด้วย ksh88 หรือ pdksh / mksh:

set -s -- "${ARRAY_DISK_Quantity[@]}"
if eval '[ "$1" = "${'"$#"'}" ]'; then
  echo OK
else
  echo not OK
fi

ด้วยbashคุณอาจต้องวนซ้ำ:

unique_values() {
  typeset i
  for i do
    [ "$1" = "$i" ] || return 1
  done
  return 0
}
if unique_values "${ARRAY_DISK_Quantity[@]}"; then
  echo OK
else
  echo not OK
fi

(จะทำงานกับเชลล์เหมือน Bourne ทั้งหมดที่มีการสนับสนุนอาร์เรย์ (ksh, zsh, bash, yash))

โปรดทราบว่ามันจะส่งคืนตกลงสำหรับอาร์เรย์ที่ว่างเปล่า เพิ่ม[ "$#" -gt 0 ] || returnที่จุดเริ่มต้นของฟังก์ชันหากคุณไม่ต้องการ


ดูเหมือนว่าคำตอบทั้งหมดเหล่านี้จะไม่สนับสนุนการทุบตี?
yael

@yael ดูการแก้ไขสำหรับวิธีทุบตี แต่ทำไมคุณจะใช้bash?
Stéphane Chazelas

ใน Bash หน้าช่วยเหลือของtypesetพูดว่าObsolete. See `help declare'.มีเหตุผลที่คุณใช้แทนlocalหรือdeclare?
wjandrea

1
@wjandrea typesetเป็นหนึ่งในเชลล์ทั้ง 4 ตัว นอกจากนี้ยังเป็นต้นฉบับจาก ksh ในช่วงต้นยุค 80 (ทุบตีส่วนใหญ่คัดลอก ksh88 เมื่อมันมาถึงการตั้งค่าตัวแปรประเภทการกำหนดขอบเขตและประกาศ แต่ตัดสินใจที่จะเปลี่ยนชื่อtypeset declareและทำให้typesetนามแฝงที่จะประกาศ)
Stéphane Chazelas

4

bash+ การawkแก้ไข:

function get_status() {
    arr=("$@")    # get the array passed as argument
    if awk 'v && $1!=v{ exit 1 }{ v=$1 }' <(printf "%d\n" "${arr[@]}"); then 
        echo "status: Ok"
    else 
        echo "status: Bad"
    fi
}

กรณีทดสอบ # 1:

ARRAY_DISK_Quantity=(4 4 4 4 4 2 4 4)
get_status "${ARRAY_DISK_Quantity[@]}"
status: Bad

กรณีทดสอบ # 2:

ARRAY_DISK_Quantity=(4 4 4 4 4 4 4 4)
get_status "${ARRAY_DISK_Quantity[@]}"
status: Ok

4

ฉันมีอีกวิธีทุบตีเท่านั้นที่ควรทำงานกับสตริงเช่นกัน:

isarray.equal () {
    local placeholder="$1"
    local num=0
    while (( $# )); do
        if [[ "$1" != "$placeholder" ]]; then
            num=1
            echo 'Bad' && break
        fi
        shift
    done
    [[ "$num" -ne 1 ]] && echo 'Okay'
}

สาธิต:

[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(4 4 4 4 2 4 4 4)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Bad
[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(4 4 4 4 4 4 4 4)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Okay
[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(four four four four two four four four)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Bad
[root@JBSTEST001 ~]# ARRAY_DISK_Quantity=(four four four four four four four four)
[root@JBSTEST001 ~]# isarray.equal "${ARRAY_DISK_Quantity[@]}"
Okay

โปรดทราบว่าจุดไม่ถูกต้องในชื่อฟังก์ชั่นแม้ว่า Bash จะได้รับอนุญาตสวย นี่อาจทำให้เกิดปัญหาเช่นในการส่งออกฟังก์ชั่น
wjandrea


2

ด้วย bash และ GNU grep:

if grep -qE '^([0-9]+)( \1)*$' <<< "${ARRAY_DISK_Quantity[@]}"; then 
  echo "okay"
else
  echo "not okay"
fi

ใช่แล้วจะเป็นอย่างไร (10 10 10 10) มิฉะนั้นค่อนข้างดี
Joe

@ โจ: จับได้ดี ฉันอัพเดตคำตอบแล้ว
Cyrus


0

bash only solution (สมมติว่าaเป็นARRAY_DISK_Quantity)

ttt=${a[0]}
res=0
for i in "${a[@]}"
do 
    let res+=$(if [ "$ttt" -ne "$i" ]; then echo 1; else echo 0; fi);  
done
if [ "$res" -eq 0 ]
then 
    echo "ok"
else
    echo "bad"
fi

ใช้งานได้ แต่จะนับข้อผิดพลาดทั้งหมดเมื่อมีเพียงหนึ่งพอ:if [ "$ttt" -ne "$i" ]; then res=1; break; fi;
โจ

0

ใช้สำหรับการวนรอบเพื่อเปรียบเทียบแต่ละองค์ประกอบอาร์เรย์กับถัดไป จบการวนซ้ำหนึ่งลูปน้อยกว่าความยาวของอาเรย์เพื่อหลีกเลี่ยงการเปรียบเทียบอิลิเมนต์สุดท้ายกับอะไรที่สิ้นสุด

for (( i=0; i<((${#array[@]}-1)); i++ )); do
    [ "${array[$i]}" != "${array[(($i+1))]}" ] && echo "Mismatch"
done
echo "Match"

ยินดีต้อนรับสู่ U&L และขอบคุณสำหรับการสนับสนุนของคุณ! รหัสนี้จะพิมพ์ "จับคู่" แม้ว่าจะพบว่าไม่ตรงกัน ... มันตั้งใจหรือไม่
ราน
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.