Use o basename para analisar uma lista de caminhos mantidos em um arquivo

7

Estou executando o Mac OSX e tentando usar a linha de comando para encontrar o número de arquivos que tenho com o mesmo nome.

Eu tentei usar o seguinte comando:

find ~ -type f -name "*" -print | basename | sort | uniq -d > duplicate_files

Não funciona! Quando faço o seguinte:

find ~ -type f -name "*" -print > duplicate_files

Em seguida, duplicate_files contém os caminhos de todos os meus arquivos. Então, acho que o problema é com basename - ele não aceita entrada padrão. Então tentei o seguinte:

basename $(find ~ -type f -name "*" -print) > duplicate_files

mas, novamente, isso parece não funcionar. A pesquisa na internet não parece produzir muita alegria. Quaisquer pensamentos mais bem vindos.

    
por JohnB 09.03.2014 / 13:01

6 respostas

13

basename opera em seu argumento de linha de comando, ele não lê da entrada padrão.

Você não precisa chamar o utilitário basename , e é melhor não: tudo o que ele faria seria remover a parte antes do último / , e seria lento chamar um comando externo para cada entrada, você pode usar um utilitário de processamento de texto.

find ~ -type f | sed 's!.*/!!' | sort | uniq -d

Pode ser mais útil acompanhar a localização dos arquivos. A classificação por nome facilita a localização de duplicados, mas sort não tem a opção de usar o último campo. O que você pode fazer é copiar o último campo / -separated para o início, depois classificar e usar um pouco de processamento ad hoc awk para extrair e apresentar as duplicatas.

find ~ -type f |
sed 's!.*/\(.*\)!/&!' |   # copy the last field to the beginning
sort -t/ -k1,1 |
cut -d/ -f2- |   # remove the extra first field (could be combined with awk below)
awk -F / '{
    if ($NF == name) {
        if (previous != "") {print previous; previous = ""}
        print
    } else {
        previous = $0
        name = $NF
    }
'

(Note que eu suponho que nenhum dos seus nomes de arquivo contém caracteres de nova linha.)

    
por 09.03.2014 / 23:24
6

Por que não usar recursos incorporados em find para gerar apenas o nome do arquivo:

find ~ -type f -printf '%f\n' | sort | uniq -c

(assume o GNU find ) ou pelo menos algo assim:

find ~ -exec basename {} \; | sort | uniq -c

basename não pode ler via pipe ou processar vários arquivos de uma só vez.

ps. Não há necessidade de especificar -name '*' se você deseja listar todos os arquivos. Esta é uma opção padrão.

    
por 09.03.2014 / 13:09
3

Isso parece funcionar para mim no OSX:

find ~ -type f -exec basename -a {} + | sort | uniq -d
    
por 09.03.2014 / 13:23
2

Alternativas (não pressupõe novas linhas nos nomes dos arquivos):

find ~ -type f | awk -F/ '{print $NF}' | sort | uniq -d
    
por 09.03.2014 / 16:18
1

Você pode usar xargs com basename para obter a saída desejada, assim:

find ~ -type f -name "*" -print | xargs -l basename | sort | uniq -d > duplicate_files
    
por 06.06.2018 / 12:59
0

Com uma versão recente de bash que lida com matrizes associativas, o seguinte também trataria de nomes de caminhos com novas linhas incorporadas:

#!/bin/bash

topdir=$HOME

shopt -s globstar  # enable the ** glob

declare -A count

# count the number of times each filename (base name) occurs
for pathname in "$topdir"/**; do
    # skip names that are not regular files (or not symbolic links to such files)
    [ ! -f "$pathname" ] && continue

    # get the base name
    filename=${pathname##*/}

    # add one to this base name's count
    count[$filename]=$(( ${count[$filename]} + 1 ))
done

# go through the collected names and print any name that
# has a count greater than one
for filename in "${!count[@]}"; do
    if [ "${count[$filename]}" -gt 1 ]; then
        printf 'Duplicate filename: %s\n' "$filename"
    fi
done

Isso não usa nenhum utilitário externo.

    
por 06.06.2018 / 13:34