เปรียบเทียบโฟลเดอร์


10

ฉันมีสองโฟลเดอร์ที่มีโครงสร้างโฟลเดอร์ย่อยที่คล้ายกันซึ่งฉันต้องการเปรียบเทียบ ตัวอย่างเช่น:

A 
├── child-1
├── child-2
├── child-3
├── child-4
├── child-5

และ

B 
├── child-1-some-text
├── child-2-more-text
├── child-3-nothing
├── child-6-random-text
├── child-7-more-random-text

ฉันต้องการแสดงรายการโฟลเดอร์ย่อยทั้งหมดAที่มีคำนำหน้าสำหรับโฟลเดอร์ย่อยBและแสดงรายการโฟลเดอร์ย่อยที่สอดคล้องกันBเช่นกัน ผลลัพธ์ที่คาดหวังคือ

child-1 -- child-1-some-text
child-2 -- child-2-more-text
child-3 -- child-3-nothing

ความต้องการรอง: หากมีการแข่งขันหลายครั้งBก็ควรให้ข้อผิดพลาด / คำเตือน

ทางออกของฉัน:

cd A
for f in `ls -d */`; 
do
    cd B;
    new_dirs=(`ls -1d $f*`);
    cd -;
    if [ ${#new_dirs[@]} -eq 0 ]
    then
        ## DO_Nothing
        continue;
    elif  [ ${#new_dirs[@]} -gt 1 ]
    then
        echo "Multiple matches to $f";
        continue;
    else
        echo "Unique Match found to $f -- ${new_dirs[0]}";
        continue;
    fi;    
done

ปัญหา:

สำหรับค่าเหล่านั้นของ$fซึ่งไม่มีโฟลเดอร์ย่อยที่สอดคล้องกันBการสร้างอาร์เรย์จะทำให้ฉันมีข้อผิดพลาด เช่น:

ls: ไม่สามารถเข้าถึง 'child-4 *': ไม่มีไฟล์หรือไดเรกทอรีดังกล่าว

คำถาม

  • จะกำจัดข้อผิดพลาดเหล่านี้ได้อย่างไร?
  • มีวิธีที่ดีกว่าในการบรรลุเป้าหมายจากนั้นเป็นเป้าหมายในรหัสของฉันหรือไม่

ขอบคุณล่วงหน้า!


4
+1 สำหรับการมอบโซลูชั่นที่ใช้งานได้จริง!
user5325

นี่ไม่ใช่คำตอบสำหรับคำถามเฉพาะของคุณ แต่คุณสามารถใช้diff -rq DIR1 DIR2เพื่อเปรียบเทียบไม่เพียง แต่โครงสร้างไดเรกทอรี แต่เนื้อหาไฟล์
jrw32982 รองรับ Monica

คำตอบ:


10

วิธีที่ดีกว่า

อย่าแยกls ; ใช้ globs แทน ในความเป็นจริงคุณกำลังใช้ globs อยู่แล้วแค่ห่อไว้lsซึ่งไม่มีประโยชน์ คุณเพียงแค่ต้องnullglobเปิดเมื่อไม่มีการแข่งขัน

ยังหลีกเลี่ยงcdสิ่งที่ทำให้ง่ายขึ้น

#!/bin/bash

shopt -s nullglob

dir1=A
dir2=B

for dir in "$dir1"/*/; do
    basename="$(basename -- "$dir")"
    dirs_match=( "$dir2/$basename"*/ )
    case ${#dirs_match[@]} in
    0)
        ;;
    1)
        echo "Unique match for $dir: ${dirs_match[*]}"
        ;;
    *)
        echo "Multiple matches for $dir: ${dirs_match[*]}" >&2
        ;;
    esac
done

เอาท์พุท:

Unique match for A/child-1/: B/child-1-some-text/
Unique match for A/child-2/: B/child-2-more-text/
Multiple matches for A/child-3/: B/child-3-nothing/ B/child-3-something/

ฉันเพิ่มB/child-3-somethingเพื่อทดสอบความต้องการรอง สิ่งนี้จะสร้างโครงสร้างไดเรกทอรีสำหรับการทดสอบ:

mkdir -p A/child-{1..5} B/child-{1-some-text,2-more-text,3-nothing,3-something,6-random-text,7-more-random-text}

โดยวิธีการShellCheckมีประโยชน์มากสำหรับการค้นหาปัญหาในเชลล์สคริปต์


ShellCheck.net น่าสนใจคุณรู้หรือไม่ว่าอัพโหลดทุกอย่างไปยังเซิร์ฟเวอร์ของตัวเองหรือทำในเครื่องทั้งหมดหรือไม่ เพียงแค่สงสัยเกี่ยวกับความเป็นส่วนตัวของข้อมูลที่ป้อน [การติดตั้งshellcheckแพคเกจจะปลอดภัยที่สุด]
Xen2050

@ Xen2050 เพิ่งลองปิดอินเทอร์เน็ตของฉันในขณะที่อยู่ในไซต์และดูเหมือนว่าจะอัปโหลด ฉันคิดว่ามันไม่ได้เก็บไว้ แต่ไม่แน่ใจ และใช่บรรจุภัณฑ์นั้นดี ฉันใช้ปลั๊กอิน Atomที่ใช้
wjandrea

ขอบคุณสำหรับคำแนะนำ ShellCheckและยังตันของขอบคุณสำหรับการชี้ไปที่ ฉันชอบส่วนที่ไม่เพียง แต่บอกข้อผิดพลาดของคุณ แต่ยังให้คำแนะนำ! @ Xen2050 เกี่ยวกับส่วนการอัปโหลดฉันเพิ่งติดตั้งshellcheckโดยใช้aptแล้วปิดการใช้งานเครือข่าย มันดูเหมือนว่าจะทำงานโดยไม่ใช้อินเทอร์เน็ต
Mike VDC

2

การโทรlsไปยังโฟลเดอร์ที่ไม่มีอยู่จะเกิดข้อความแสดงข้อผิดพลาดที่คุณพบ วิธีที่ง่ายคือเพียงแค่สนใจนี้โดยการเปลี่ยนสาย 5 new_dirs=(`ls -1d $f* 2> /dev/null`);ในสคริปต์ของคุณด้วยนี้


คุณเคยทดสอบสิ่งนี้หรือไม่? Stderr ดูเหมือนว่าจะถูกละเว้นโดยค่าเริ่มต้นเมื่อฉันเรียกใช้t=(`echo ok; echo err 1>&2`)$ t (หรือ${t[@]}) มี ok เท่านั้นจะเห็น err ใน terminal แต่ไม่ได้บันทึกไว้ หรือมีบางอย่างตลกเกี่ยวกับการทดสอบของฉันได้อย่างไร
Xen2050
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.