Порівняння папок


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 за надання майже працюючого рішення!
користувач5325

Це не відповідь на ваше конкретне питання, але ви можете використовувати diff -rq DIR1 DIR2для порівняння не просто структури каталогів, а вмісту файлу.
jrw32982 підтримує Моніку

Відповіді:


10

Кращий спосіб

Не розбирайтеls ; використовувати замість глобусів. Насправді ви вже використовуєте глобуси, просто загортаючи їх 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та відключивши мережу. Здається, працює без Інтернету .
Майк VDC

2

Виклик lsу неіснуючій папці видає повідомлення про помилку, яке ви зіткнулися. Найпростіший спосіб це просто ігнорувати це, замінивши рядок 5 в сценарії з цим: new_dirs=(`ls -1d $f* 2> /dev/null`);.


Ви перевірили це? Схоже, Stderr ігнорується за замовчуванням, коли я запускаю, що t=(`echo ok; echo err 1>&2`)$ t (або ${t[@]}) містить лише нормально, помилка помічена в терміналі, але не зберігається. Або є щось смішне в моєму тесті?
Xen2050
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.