Como executo um diff de nomes de arquivos curtos?

2

Estou usando o shell bash. Eu quero ver um diff de nomes de arquivos em dois diretórios, mas apenas dos filhos diretos desses diretórios. Então, por exemplo, se eu tenho esses diretórios com arquivos / pastas filho nomeados ...

dir1
-> abc
-> def
-> ghi

dir2
-> abc
-> fff
-> ghi

Eu gostaria de poder executar algum comando que me diria que o dir2 tem um arquivo / dir chamado "fff" que o dir1 não tem, ao passo que "dir1" tem um arquivo / dir filho chamado "def" que dir2 não tem. Como faço isso?

    
por Dave 19.09.2017 / 20:34

2 respostas

1

for name in dir1/* dir2/*; do
    bname=${name##*/}

    if [ ! -e "dir1/$bname" ]; then
        printf '"%s" not in dir1\n' "$bname"
    elif [ ! -e "dir2/$bname" ]; then
        printf '"%s" not in dir2\n' "$bname"
    fi
done

Isso iterará todos os nomes em dir1 e dir2 . $bname será o nome da base do nome ( $name sem caminho).

Se o nome (base) não puder ser encontrado em dir1 , isso será relatado. Caso contrário, se não for encontrado em dir2 , será relatado.

Isso lida com nomes de arquivos que contêm novas linhas incorporadas e deve ser executado com /bin/sh ou qualquer shell sh compatível.

Isso poderia ser expandido para mais de dois diretórios. Com bash :

dirs=( dir1 dir2 dir3 dir4 )

for dir in "${dirs[@]}"; do
    for name in "$dir"/*; do

        bname=${name##*/}

        for tdir in "${dirs[@]}"; do
            if [ ! -e "$tdir/$bname" ]; then
                printf '"%s" not found in %s\n' "$bname" "$tdir"
            fi
        done

    done
done
$ tree
.
|-- dir1
|   '-- filename 1
|-- dir2
|   |-- filename 1
|   |-- filename 3
|   '-- hello
world
'-- script.sh

$ sh script.sh
"filename 3" not in dir1
"hello
world" not in dir1
    
por 19.09.2017 / 21:01
0

Por isso eu gosto muito de comm -3 , na saída de ls :

$ comm -3 <(ls dir1) <(ls dir2)
def
        fff

As entradas na primeira coluna são apenas no primeiro diretório, as entradas na segunda coluna são apenas no segundo diretório; a opção -3 remove a terceira coluna que exibe entradas comuns a ambas. Você também pode especificar -1 para ver apenas os arquivos presentes em dir2 , mas não em dir1 , e -2 para ver apenas os arquivos presentes em dir1 , mas não em dir2 .

Para que isso funcione, é necessário garantir que você não tenha opções definidas para ls , via sua configuração OPTIONS ou um alias. Você pode evitar esses problemas usando uma variante como

$ comm -z -3 <(cd dir1; printf "%s
$ comm -3 <(ls dir1) <(ls dir2)
def
        fff
" *) <(cd dir2; printf "%s
$ comm -z -3 <(cd dir1; printf "%s%pre%" *) <(cd dir2; printf "%s%pre%" *) | tr '%pre%' '\n'
def
        fff
" *) | tr '%pre%' '\n' def fff

O último evita problemas com caracteres especiais em nomes de arquivos. Você pode combiná-lo com -1 ou -2 e descartar tr para alimentá-lo em xargs -0 para processamento adicional de qualquer conjunto de arquivos também.

    
por 19.09.2017 / 20:52