Localiza arquivos cujos nomes são os mesmos, mas seus nomes ext não são

6

Em um diretório, como podemos encontrar todos os arquivos cujos nomes base são os mesmos, mas os nomes das extensões não são? Por exemplo. 0001.jpg e 0001.png e 0001.tiff e 0002.jpg e 0002.png .

    
por Tim 14.11.2014 / 01:21

6 respostas

7

Se você quiser todos os nomes de arquivos exclusivos, aqui vai:

ls -1 | sed 's/\([^.]*\).*//' | uniq

Se você quiser que os arquivos de tal forma que mais de um deles tenham o mesmo nome de base, use:

ls -1 | sed 's/\([^.]*\).*//' | uniq -c | sort -n | egrep -v "^ *\<1\>"

Para nomes de arquivos com vários períodos, use o seguinte:

ls -1 | sed 's/\(.*\)\..*//' | uniq -c | sort -n | egrep -v "^ *\<1\>"
    
por 14.11.2014 / 01:51
4

Uma solução que usa (evito analisar ls output, não é projetado para esta tarefa e pode causar bugs):

perl -E '
    while (<*>){
        ($full, $short) = (m/^((.*?)\..*)$/);
        next unless $short;
        push @{ $h->{$short} }, $full;
    }
    for $key (keys %$h) {
        say join " ", @{ $h->{$key} } if @{ $h->{$key} } > 1;
    }
' /home/sputnick

substitua /home/sputnick por . ou qualquer diretório desejado;)

    
por 14.11.2014 / 01:35
3

Como as únicas respostas aqui usam sed ou perl e expressões regulares, eu pensei que seria diferente e postaria algo muito mais simples.

for file in /path/to/your/files/*; do echo ${file%%.*}; done | uniq -d

Neste exemplo, ${file%%.*} corresponde ao caminho do arquivo até o primeiro período ( . ). Então, 0001.tar.gz seria tratado como 0001 .

A saída ficaria assim

/path/to/your/files/0001
/path/to/your/files/0002

Se você não quiser o caminho completo na saída, simplesmente cd no diretório primeiro e depois execute o comando com apenas um asterisco ( * ) para o caminho.

cd /path/to/your/files
for file in *; do echo ${file%%.*}; done | uniq -d

Em seguida, a saída ficaria assim

0001
0002
    
por 14.11.2014 / 04:25
2

Se você tem um ambiente GNU, aqui está uma solução robusta que imprime os nomes básicos comuns, usando gawk (apenas para misturar):

find . -maxdepth 1 -type f -printf "%f
find . -maxdepth 1 -type f -name "*.*" -printf "%f
find . -maxdepth 1 -type f -name "*.*" -printf "%f
find . -maxdepth 1 -type f -printf "%f
find . -maxdepth 1 -type f -name "*.*" -printf "%f
find . -maxdepth 1 -type f -name "*.*" -printf "%f%pre%" |        
  gawk 'BEGIN{ RS="%pre%" } 
             { base=$0;sub(/\.[^.]+$/,"",base);seen[base][FNR]=$0} 
        END  { for (bb in seen) 
                 if (length(seen[bb])>1) 
                    for (ff in seen[bb]) printf("%s%pre%",seen[bb][ff])
              }' |    
  tr '%pre%0' '\n'
" | ...
" | gawk 'BEGIN{RS="%pre%"} {sub(/\.[^.]+$/,""); if (length($0))printf("%s%pre%",$0)}' | sort -z | uniq -zd | tr '%pre%0' '\n'
" | gawk 'BEGIN{ RS="%pre%" } { base=$0;sub(/\.[^.]+$/,"",base);seen[base][FNR]=$0} END { for (bb in seen) if (length(seen[bb])>1) for (ff in seen[bb]) printf("%s%pre%",seen[bb][ff]) }' | tr '%pre%0' '\n'
" | ...
" | gawk 'BEGIN{RS="%pre%"} {sub(/\.[^.]+$/,""); if (length($0))printf("%s%pre%",$0)}' | sort -z | uniq -zd | tr '%pre%0' '\n'

Isso usa find com \ 0 (nul) nomes de arquivos delimitados, gawk com RS (separador de registro) definido como \ 0 para corresponder à entrada e sub(/regex/) para remover uma extensão.

O comando final tr desfaz a delimitação nula para impressão na tela, omite isso para processamento adicional (seguro) de nomes de arquivos .

(Normalmente eu faria algo como whatever | rev | cut -d. -f2- | rev | sort , mas rev não faz uma entrada delimitada por nul.)

Se você quiser limitá-lo apenas a arquivos com um padrão .ext ou mais específico, use:

%pre%

A primeira opção acima apenas imprime a base comum, se você quiser imprimir os nomes reais dos arquivos:

%pre%

(mínimo requerido do gawk v4.0 para matrizes multidimensionais!)

Isso usa uma matriz (hash) seen[] para armazenar em cache os nomes de arquivos vistos pelo nome base e, no final, itera sobre os nomes base em seen[bb] e imprime aqueles com mais de correspondência ( length(seen[bb])>1 ).

    
por 14.11.2014 / 13:11
1

Se você não tem medo de analisar ls :

/bin/ls --color=no -1 | sed 's/\.[^.]*$//' | uniq -d

Isso falhará se os nomes dos arquivos contiverem novas linhas.

    
por 14.11.2014 / 02:23
1
ls -1 | awk -F'.' '{print $1}'|uniq -cd

o awk imprime o primeiro campo ( $1 ) de cada arquivo com o separador de campo . .

uniq -d fornece apenas as linhas duplicadas e, com a opção -c , imprime o número de ocorrências.

$ ls -1
 0001.jpg
 0001.tar.gz 
 0001.tiff
 0002.png
 0002.tar.bz2
 001.zip
$ ls -1 | awk -F'.' '{print $1}'|uniq -cd
 3 0001
 2 0002
    
por 14.11.2014 / 21:14

Tags