linha de comando do Linux: glob confusion

5

Estou tentando entender o linux, sua linha de comando e esta frase:

You can run into problems with globs because .* matches . and .. (the current and parent directories). You may wish to use a pattern such as .[^.]* or .??* to get all dot files except the current and parent directories.

Quando exatamente (em qual comando) você usaria .[^.]* ou .??* ?

    
por Jackelline J. 15.09.2017 / 17:08

2 respostas

9

Isso é para contornar um bug / falta de má qualidade em shells diferentes de zsh , fish e os descendentes do shell Forsyth (incluindo pdksh e derivativos), pelo qual o .* globs inclui . e .. (em sistemas (mais, infelizmente) onde readdir() os retorna)

Com essas conchas,

chmod -R og-rwx .*

por exemplo, removeria recursivamente as permissões rwx para o diretório atual e pai, em vez de apenas os arquivos e diretórios ocultos no diretório atual. Foi necessário adicionar um trabalho a rm , pois muitas pessoas tropeçaram em rm -rf .* .

Também é (provavelmente mais frequentemente) usado para passar todos os arquivos (ocultos ou não) como argumentos para um comando ( cmd .[!.]* ..?* * ), para o qual você encontrará outras soluções alternativas dependendo do shell .

É particularmente ruim para comandos que fazem coisas recursivamente ou agem em diretórios como ls .* , chown -R .* , find .* , grep -r blah .* , mas ainda é irritante para a maioria dos outros comandos e não consigo pensar em nenhum comando para qual você gostaria de ter os . e .. incluídos na lista de arquivos passados para eles.

O .[^.]* glob ( .[!.]* em shells Bourne / POSIX) exclui . (como corresponde em nomes de arquivos com pelo menos dois caracteres) e .. (como o segundo caractere é . que não faz t match [^.] ), mas também exclui arquivos como ..foo , para o qual você precisa da segunda glob ..?* .

Esses . e .. são ferramentas para a travessia de diretórios, é um erro que eles devem ser listados como arquivos comuns. O POSIX exige que eles sejam compreendidos nos componentes do caminho (como em open(".") , stat("foo/../bar") ), mas não necessariamente implementados como entradas de diretório nem incluídos em readdir() .

Ainda assim, a maioria dos sistemas ainda implementa aqueles como no início do Unices como hard links, e aqueles que não o fazem ainda falsificam entradas para eles na saída de getdents() / readdir() .

Com bash , uma alternativa é ativar a opção dotglob e usar:

chmod -R og-rwx [.]*

(embora tenha cuidado, se não houver nenhum arquivo não oculto, ele poderá alterar as permissões do arquivo [.]* , a menos que você tenha a opção failglob para imitar o comportamento de zsh / fish ).

Como uma observação do histórico, o nome de arquivo começando com . sendo arquivos ocultos era nascido de um erro de codificação de alguém tentando ignorar . e .. em primeiro lugar . É irônico que, ao tentar fazer coisas com arquivos ocultos, tenhamos o mesmo problema.

    
por 15.09.2017 / 17:27
5

Quando quiser mover todos os arquivos e diretórios com nomes ocultos (começando com um ponto) para outro local:

mv .[^.]* old-dot-files/

Ou, sempre que quiser fazer algo em todos os arquivos de ponto ou de ponto em um diretório:

for name in .[^.]*; do
   # process "$name"
done

Observe que o padrão .??* exige que os nomes correspondentes tenham pelo menos três caracteres, portanto, nomes como .a não serão selecionados. .[^.]* , por outro lado, pulará qualquer coisa com um ponto duplo no início do nome.

Pode ser melhor testar explicitamente os nomes correspondentes:

for name in .*; do
    # expecting a regular file
    if [ -f "$name" ]; then
        # process "$name"
    fi
done

for name in .*; do
    # expecting a directory other than . and ..
    if [ -d "$name" ] && [ "$name" != '.' ] && [ "$name != '..' ]; then
        # process "$name"
    fi
done

Na minha experiência, querer fazer algo com todos os diretórios de ponto ou arquivo de ponto em um diretório acontece raramente.

    
por 15.09.2017 / 17:16