Confronto delle cartelle


10

Ho due cartelle con strutture di sottocartella simili, che vorrei confrontare. Per esempio:

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

e

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

Vorrei elencare tutte quelle sottocartelle da Acui sono prefissi una sottocartella Be anche elencare le relative sottocartelle B. L'output previsto è

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

Un requisito secondario: se si verificano più corrispondenze B, dovrebbe essere visualizzato un errore / avviso.

La mia soluzione :

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

Problema:

Per quei valori di $f, che non hanno sottocartelle corrispondenti in B, la costruzione dell'array mi sta dando un errore. per esempio:

ls: impossibile accedere a "child-4 *": nessun file o directory

Domanda

  • Come sbarazzarsi di questi errori?
  • Esiste un modo migliore per raggiungere gli obiettivi rispetto a quello nel mio codice?

Grazie in anticipo!


4
+1 per fornire una soluzione quasi funzionante!
user5325

Questa non è una risposta alla tua domanda specifica, ma puoi usare diff -rq DIR1 DIR2per confrontare non solo la struttura delle directory, ma i contenuti dei file.
jrw32982 supporta Monica

Risposte:


10

Il modo migliore

Non analizzarels ; usa invece globs. In effetti stai già usando globs, semplicemente avvolgendoli ls, il che è inutile. Devi solo nullglobaccenderlo per quando non ci sono partite.

Evitare anche cdsemplifica le cose.

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

Produzione:

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/

Ho aggiunto B/child-3-somethingper testare il requisito secondario. Questo crea la struttura di directory per il test:

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}

A proposito, ShellCheck è molto utile per trovare problemi negli script di shell.


ShellCheck.net è interessante, sai se carica tutto sui suoi server o è tutto fatto localmente? Mi chiedo solo sulla privacy delle informazioni inserite. [L'installazione del shellcheckpacchetto sarebbe la più sicura]
Xen2050

@ Xen2050 Ho appena provato a disattivare la mia connessione Internet mentre sul sito sembra caricarsi. Immagino che non lo tenga, ma non ne sono sicuro. E sì, il pacchetto è buono; Uso un plugin Atom che lo utilizza.
wjandrea,

Grazie per i suggerimenti E anche un sacco di ringraziamenti per aver puntato verso ShellCheck. Ho adorato la parte in cui non solo ti dice i tuoi errori, ma dà anche suggerimenti! @ Xen2050, per quanto riguarda la parte di caricamento, ho appena installato shellcheckutilizzando apte quindi disabilitato la rete. Sembra funzionare senza internet .
Mike VDC,

2

Chiamare lsuna cartella inesistente genera il messaggio di errore che hai riscontrato. Il modo più semplice è quello di ignorare proprio questo, sostituendo la linea 5 nello script con questo: new_dirs=(`ls -1d $f* 2> /dev/null`);.


Hai provato questo? Stderr sembra essere ignorato di default, quando eseguo t=(`echo ok; echo err 1>&2`)$ t (o ${t[@]}) contiene solo ok, err viene visualizzato nel terminale ma non salvato comunque. O c'è qualcosa di divertente nel mio test?
Xen2050,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.