Comparação de pastas


10

Eu tenho duas pastas com estruturas de subpastas semelhantes, que eu gostaria de comparar. Por exemplo:

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

Gostaria de listar todas as subpastas das Aquais são prefixos para uma subpasta Be também listar as subpastas correspondentes B. A saída esperada é

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

Um requisito secundário: se houver várias correspondências B, deve ocorrer um erro / aviso.

Minha solução :

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:

Para os valores de $f, que não possuem subpastas correspondentes B, a construção da matriz está me causando um erro. por exemplo:

ls: não é possível acessar 'child-4 *': esse arquivo ou diretório não existe

Questão

  • Como se livrar desses erros?
  • Existe uma maneira melhor de atingir o (s) objetivo (s) do que aquele no meu código?

Desde já, obrigado!


4
+1 por fornecer uma solução quase funcional!
user5325

Esta não é uma resposta para sua pergunta específica, mas você pode usar diff -rq DIR1 DIR2para comparar não apenas a estrutura de diretórios, mas o conteúdo do arquivo.
Jrw32982 suporta Monica

Respostas:


10

A melhor maneira

Não analisels ; use globs em vez disso. Na verdade, você já está usando globs, apenas envolvê-los ls, o que é inútil. Você só precisa nullglobativar para quando não há correspondências.

Evitar também cdsimplifica as coisas.

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

Resultado:

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/

Eu adicionei B/child-3-somethingpara testar o requisito secundário. Isso cria a estrutura de diretórios para teste:

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 propósito, o ShellCheck é muito útil para encontrar problemas nos scripts de shell.


O ShellCheck.net é interessante, você sabe se ele envia tudo para seus próprios servidores ou tudo é feito localmente? Apenas querendo saber sobre a privacidade das informações inseridas. [Instalando o shellcheckpacote seria o mais seguro]
Xen2050

@ Xen2050 Tentei desligar minha internet enquanto estava no site, e parece que ele foi carregado. Eu imagino que não mantém, mas não tenho certeza. E sim, o pacote é bom; Eu uso um plugin Atom que o usa.
21419 wjandrea

Obrigado pelas sugestões. E também muito obrigado por apontar ShellCheck. Adorei a parte em que ela não apenas informa seus erros, mas também dá sugestões! @ Xen2050, sobre a parte de upload, eu acabei de instalar shellcheckusando apte depois desabilitei a rede. Parece estar funcionando sem internet .
Mike VDC

2

Chamar lsuma pasta inexistente lança a mensagem de erro que você encontrou. A maneira mais fácil é simplesmente ignorar isso, substituindo a linha 5 em seu script com este: new_dirs=(`ls -1d $f* 2> /dev/null`);.


Você já testou isso? O Stderr parece ser ignorado por padrão, quando eu executo t=(`echo ok; echo err 1>&2`)$ t (ou ${t[@]}) contém apenas ok, o erro é visto no terminal, mas não é salvo de qualquer maneira. Ou há algo engraçado no meu teste?
Xen2050 25/03/19
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.