So sánh thư mục


10

Tôi có hai thư mục có cấu trúc thư mục con tương tự, mà tôi muốn so sánh. Ví dụ:

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

Tôi muốn liệt kê tất cả các thư mục con từ Ađó là tiền tố cho thư mục con trong Bvà liệt kê cả các thư mục con tương ứng B. Sản lượng dự kiến ​​là

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

Yêu cầu phụ: Nếu có nhiều kết quả trùng khớp B, thì nó sẽ đưa ra lỗi / cảnh báo.

Giải pháp của tôi :

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

Vấn đề:

Đối với các giá trị $fđó, không có thư mục con tương ứng B, việc xây dựng mảng sẽ gây ra lỗi cho tôi. ví dụ:

ls: không thể truy cập 'child-4 *': Không có tệp hoặc thư mục như vậy

Câu hỏi

  • Làm thế nào để thoát khỏi những lỗi này?
  • Có cách nào tốt hơn để đạt được (các) mục tiêu sau đó là mục tiêu trong mã của tôi không?

Cảm ơn trước!


4
+1 để cung cấp một giải pháp gần như làm việc!
dùng5325

Đây không phải là một câu trả lời cho câu hỏi cụ thể của bạn, nhưng bạn có thể sử dụng diff -rq DIR1 DIR2để so sánh không chỉ cấu trúc thư mục, mà cả nội dung tệp.
jrw32982 hỗ trợ Monica

Câu trả lời:


10

Cách tốt hơn

Đừng phân tích cú phápls ; sử dụng quả cầu thay thế. Trong thực tế, bạn đã sử dụng các khối, chỉ cần gói chúng vào ls, điều này là vô nghĩa. Bạn chỉ cần nullglobbật khi không có trận đấu.

Cũng tránh cdđơn giản hóa mọi thứ.

#!/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

Đầu ra:

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/

Tôi đã thêm B/child-3-somethingđể kiểm tra các yêu cầu thứ cấp. Điều này tạo ra cấu trúc thư mục để thử nghiệm:

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}

Nhân tiện, ShellCheck rất hữu ích cho việc tìm kiếm các vấn đề trong các kịch bản shell.


ShellCheck.net rất thú vị, bạn có biết nếu nó tải mọi thứ lên máy chủ của chính nó hay tất cả được thực hiện tại địa phương? Chỉ cần tự hỏi về sự riêng tư của thông tin nhập. [Cài đặt shellcheckgói sẽ an toàn nhất]
Xen2050

@ Xen2050 Chỉ cần cố gắng tắt internet của tôi khi ở trên trang web và nó dường như tải lên. Tôi sẽ tưởng tượng nó không giữ nó, nhưng không chắc chắn. Và có gói là tốt; Tôi sử dụng một plugin Atom sử dụng nó.
wjandrea

Cảm ơn những lời đề nghị. Và cũng tấn tấn cảm ơn đã chỉ về phía ShellCheck. Tôi yêu phần mà nó không chỉ cho bạn biết lỗi của bạn, mà còn đưa ra gợi ý! @ Xen2050, về phần tải lên, tôi chỉ cần cài đặt shellcheckbằng cách sử dụng aptvà sau đó vô hiệu hóa mạng. Nó dường như được làm việc mà không có internet .
Mike VDC

2

Gọi lsvào một thư mục không tồn tại sẽ ném thông báo lỗi mà bạn gặp phải. Cách dễ dàng là chỉ cần bỏ qua điều này bằng cách thay thế dòng 5 trong tập lệnh của bạn bằng : new_dirs=(`ls -1d $f* 2> /dev/null`);.


Bạn đã thử nghiệm điều này? Stderr dường như bị bỏ qua theo mặc định, khi tôi chạy t=(`echo ok; echo err 1>&2`)$ t (hoặc ${t[@]}) chỉ chứa ok, lỗi được nhìn thấy trong thiết bị đầu cuối nhưng dù sao không được lưu. Hoặc có điều gì đó buồn cười về bài kiểm tra của tôi?
Xen2050
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.