Como encontrar todos os caminhos não compatíveis com o Windows?

6

Na maioria dos sistemas de arquivos Linux, o NUL ( / ) é o único caractere inválido em caminhos (e %code% é reservado como o separador de caminho). O Windows possui um conjunto complicado de regras para caminhos válidos . Em vez de corrigir os caminhos automaticamente (perigoso, pode resultar em um arquivo sobrescrevendo outro), como posso encontrar todos os caminhos dentro de um diretório não compatível com o Windows?

O problema original era que a minha pasta Google Drive estava em uma unidade montada usando ext2fs , mas o cliente oficial do Gdrive me disse que milhares de arquivos não poderiam ser sincronizados. Eu não encontrei nenhuma mensagem de erro, e quando pedi para mostrar os arquivos, ela simplesmente ficava pendurada indefinidamente. Reiniciar o cliente ou o sistema operacional não ajudou, mas eu tinha um palpite de corrigir quaisquer caminhos não compatíveis com o Windows Gdrive Parece ter funcionado ...

    
por l0b0 24.05.2014 / 23:26

2 respostas

3

Caminhos com nomes / caracteres reservados:

LC_ALL=C find . -name '*[[:cntrl:]<>:"\|?*]*' \
             -o -iname 'CON' \
             -o -iname 'PRN' \
             -o -iname 'AUX' \
             -o -iname 'NUL' \
             -o -iname 'COM[1-9]' \
             -o -iname 'LPT[1-9]' \
             -o -name '* ' \
             -o -name '?*.'

Teste:

$ cd -- "$(mktemp --directory)"
$ touch foo \ LPT9 'space ' 'dot.'
$ LC_ALL=C find . -name '*[[:cntrl:]<>:"\|?*]*' -o -iname 'CON' -o -iname 'PRN' -o -iname 'AUX' -o -iname 'NUL' -o -iname 'COM[1-9]' -o -iname 'LPT[1-9]' -o -name '* ' -o -name '?*.'
./dot.
./space 
./LPT9
./\

Caminhos que são idênticos ao ignorar maiúsculas e minúsculas ( não funciona com caminhos contendo novas linhas ):

find . | sort | LC_ALL=C tr '[:upper:]' '[:lower:]' | uniq -c | grep -v '^      1 ' | cut -c '9-'

Teste:

$ cd -- "$(mktemp --directory)"
$ touch foo bar BAR
$ find . | sort | LC_ALL=C tr '[:upper:]' '[:lower:]' | LC_ALL=C uniq -c | grep -v '^      1 ' | cut -c '9-'
./bar

Caminhos com mais de MAX_PATH (260 caracteres):

find "$PWD" | while IFS= read -r path
do
    if [ "${#path}" -gt 260 ]
    then
        printf '%s\n' "$path"
    fi
done

Teste:

$ cd -- "$(mktemp --directory)"
$ touch foo 123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
$ find "$PWD" | while IFS= read -r path
> do
>     if [ "${#path}" -gt 260 ]
>     then
>         printf '%s\n' "$path"
>     fi
> done
/tmp/tmp.HEANyAI8Hy/123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345
    
por 24.05.2014 / 23:26
-1

Para uma solução Perl, você pode usar o módulo Win32::Filenames para isso.

link

Um programa simples usando este módulo:

#!/usr/bin/env perl

use strict;
use warnings;

use Win32::Filenames qw(validate sanitize);

while ( my $filename = shift ) {
    printf( "checking filename %s\t", $filename );

    if ( validate($filename) ) {
        print("ok.\n");
    }
    else {
        printf( "failed, try this instead: %s\n", sanitize($filename) );
    }
}

Você o invoca com um ou vários nomes de arquivo na linha de comando:

$ ./check.pl '<a>' 'hi?' '"right"' 'pipe|me'
checking filename <a>   failed, try this instead: -a-
checking filename hi?   failed, try this instead: hi-
checking filename "right"       failed, try this instead: -right-
checking filename pipe|me       failed, try this instead: pipe-me

Para toda uma hierarquia de arquivos:

$ find . -exec basename {} \; | xargs ./check.pl
    
por 28.05.2015 / 12:55