Usando o curinga no comando 'ls' para localizar arquivos contendo apenas letras maiúsculas

0

Por isso andei brincando com o sistema de arquivos e me perguntei sobre listar os arquivos em /etc que contém apenas letras maiúsculas em seus nomes. Eu comandei

ls *[A-Z]* 

Mas o console também mostra os arquivos contendo caracteres menores. Eu quero usar apenas o comando ls . O locale do programa de console é dependente?

Qual é a causa subjacente?

    
por Akash_Triv3di 29.08.2017 / 14:43

6 respostas

2

[A-Z] não significa letras maiúsculas. Isso significa letras de A a Z , que podem incluir letras minúsculas. Normalmente você deve usar [[:upper:]] . (Isso funciona no Bash mesmo sem extglob .)

Quais caracteres [A-Z] correspondem à sua localidade.

Você esclareceu que você deseja mostrar todos os nomes de arquivos que contenham pelo menos caracteres maiúsculos em qualquer lugar - não apenas nomes de arquivos consistindo inteiramente de letras maiúsculas - mas que quando você usa ls *[A-Z]* , você obtém alguns nomes de arquivos que não têm nenhum caracteres maiúsculos neles.

Isso acontece quando a ordenação lexicográfica do seu código do idioma interpõe letras maiúsculas e minúsculas (por exemplo, AaBbCcDd ...). Embora você possa definir outro local (por exemplo, LC_ALL=C ), a melhor solução é escrever um padrão que corresponda especificamente às letras maiúsculas.

Quais caracteres são letras maiúsculas também podem variar entre as localidades, mas presumivelmente se algo for uma letra maiúscula na sua localidade, você deseja incluí-la. Então, isso é provavelmente uma vantagem de [[:upper:]] em vez de uma desvantagem.

Use [[:upper:]] .

A maioria dos shells no estilo Bourne, como o Bash, suporta classes de caracteres POSIX em globs. Este comando listará as entradas em /etc cujos nomes têm pelo menos uma letra maiúscula:

ls -d /etc/*[[:upper:]]*

Algumas das entradas que você recebe podem ser diretórios. Se você deseja mostrar seu conteúdo em vez de apenas listar os diretórios, você pode remover o sinalizador -d . Você também pode colocar um sinalizador -- antes do padrão, caso tenha entradas em /etc que começam com - . Você provavelmente não, no entanto. (Em um script, você geralmente desejará usar -- aqui.)

Você provavelmente não quer dotfiles, mas se você quiser ...

Isso não mostrará entradas que começam com . . Normalmente você não quer mostrá-los. Se você quiser, a maioria dos shells permite que você escreva um único glob que também os corresponda ou configure o globbing para incluí-los por padrão. A opção de incluir automaticamente as entradas de lead- . no Bash é dotglob e pode ser ativada com shopt -s dotglob . Para outras granadas, consulte . Ou você pode simplesmente escrever uma segunda glob para eles:

ls -d /etc/*[[:upper:]]* /etc/.*[[:upper:]]*

As cascas de estilo Bourne mais populares suportam expansões de chaves, para que você possa escrever isso mais compactamente com menos repetição:

ls -d /etc/{,.}*[[:upper:]]*

Na maioria dos shells, incluindo Bash, quando você escreve dois globs separados, você recebe uma mensagem de erro quando um deles não expande - porque o comportamento padrão na maioria dos shells é passá-lo não expandido. Mas ls ainda mostrará as entradas que corresponderam à outra. Mas como Stéphane Chazelas apontou , em alguns shells, incluindo o muito popular Zsh, todo o comando falha e ls nunca é executado. Se você estiver usando o shell interativamente, isso não é realmente prejudicial, porque você pode modificar o comando executá-lo novamente, mas essas construções são inadequadas para scripts portáteis. O Bash também se comportará dessa maneira se você definir a opção failglob shell.

Você não precisa de ampliação para isso.

No Bash, você não precisa ter o globbing estendido ativado para usar classes de caracteres POSIX em padrões glob. No meu sistema com o Bash 4.3.48:

ek@Io:~$ shopt extglob
extglob         off
ek@Io:~$ ls -d /etc/*[[:upper:]]*
/etc/ConsoleKit     /etc/LatexMk         /etc/ODBCDataSources  /etc/UPower
/etc/ImageMagick-6  /etc/NetworkManager  /etc/rcS.d            /etc/X11

Mas é necessário que você corresponda a nomes de arquivos de somente letras maiúsculas.

O que você faz precisa de globalização estendida é se você deseja combinar nomes de arquivos consistindo somente de letras maiúsculas. Então você usaria +([[:upper:]]) ou *([[:upper:]]) , e esses são globs estendidos.

Se você estiver usando o Bash, consulte este artigo , este guia , 3.5.8.1 Combinação de padrões no manual do GNU Bash para detalhes. Veja também a resposta de Stéphane Chazelas .

    
por 29.08.2017 / 15:16
2

Para nomes de arquivos consistindo apenas de letras maiúsculas.

(como FOO , ÉTÉ , ΛΈΞΗ ; ao contrário de FOO.BAR , ÉTÉ (onde É é escrito como E seguido por um U + 0301 combinando acento agudo¹))

Com ksh ou zsh -o kshglob -o nobareglobqual ou bash -O extglob :

ls -d +([[:upper:]])

Com zsh -o extendedglob (que você prefere usar em vez de kshglob ):

ls -d [[:upper:]]#

Ou com o GNU ls (assumindo que os nomes dos arquivos contenham apenas caracteres válidos):

ls --ignore='*[^[:upper:]]*'

Ou com find em vez de ls (que aqui apenas exibe seus argumentos, eu esperaria que você queira usar opções como -l para que seja útil):

find . ! -name . -prune -name '*' ! -name '*[^[:upper:]]*'

(o -name '*' é filtrar os nomes dos arquivos que contêm caracteres inválidos, que o próximo ! -name não conseguirá filtrar (com pelo menos find implementações))

para nomes de arquivos sem letras minúsculas

(mas ainda permite não-letras como em ABC.TXT ), com ksh :

(FIGNORE='@(.|..|*[[:lower:]]*)'; ls -d -- *)

com bash -O dotglob -O extglob ou zsh -o kshglob -o dotglob -o nobareglobqual :

ls -d -- !(*[[:lower:]]*)

Ou zsh -o extendedglob :

ls -d -- ^*[[:lower:]]*(D)

Ou com o GNU ls (assumindo que os nomes dos arquivos contenham apenas caracteres válidos):

ls -A --ignore='*[[:lower:]]*' --ignore='.*[[:lower:]]*'

(o fato de que o --ignore='.*[[:lower:]]*' extra é necessário parece um erro para mim)

com find :

find . ! -name . -prune -name '*' ! -name '*[[:lower:]]*'

(com algumas implementações de find , não inclui nomes de arquivos com caracteres inválidos, mesmo que nenhum dos caracteres válidos seja de minúsculas).

Para nomes de arquivos com pelo menos uma letra maiúscula:

(como Foo.bar , .Été.txt , ao contrário de 123.6 , foo.bar )

Com zsh -o dotglob ou bash -O dotglob (sendo o dotglob incluir arquivos cujo nome comece com . ):

ls -d -- *[[:upper:]]*

com find :

find . ! -name . -prune -name '*[[:upper:]]*'

(com algumas implementações de find , não inclui nomes de arquivos com caracteres inválidos, mesmo se alguns dos caracteres válidos forem caracteres maiúsculos)

¹ Para permitir a combinação de caracteres, com zsh -o pcrematch , você poderia usar uma expressão regular semelhante a um perl, fazendo uso de propriedades de caracteres Unicode:

ls -d -- *(e@'[[ $REPLY =~ "^(?>\p{Lu}\pM*)*$" ]]'@)
    
por 29.08.2017 / 15:10
0

Perdoe-me pela resposta anterior, eu não tomei meu café ainda.

Não tenho certeza sobre como fazer isso com apenas ls. Mas, aqui está outro grep que deve fazer o truque:

ls | egrep ^ [^ a-z0-9] * $

    
por 29.08.2017 / 14:59
0

O padrão do seu comando corresponderá a qualquer nome de arquivo com pelo menos uma letra maiúscula: Foo ou bAr corresponderá, porque o * pode corresponder a tudo antes ou depois da letra maiúscula. É por isso que você também obtém arquivos com também letras minúsculas no nome.

Se você quiser arquivos com apenas letras maiúsculas, precisará de extglob in bash :

shopt -s extglob

e depois faça

ls *([A-Z])

Você também pode precisar definir sua localidade como C ou usar [:upper:] em vez de A-Z

    
por 29.08.2017 / 15:12
0

Por que você quer usar apenas ls? Você pode simplesmente usar a localização: find -regex './[A-Z]+'

EDIT:
De acordo com man 7 glob :

Wildcard matching
A string is a wildcard pattern if it contains one of the characters '?', '*' or '['. Globbing is the operation that expands a wildcard pattern into the list of pathnames matching the pattern. Matching is defined by:

A '?' (not between brackets) matches any single character.

A '*' (not between brackets) matches any string, including the empty string.

Character classes

An expression "[...]" where the first character after the leading '[' is not an '!' matches a single character, namely any of the characters enclosed by the brackets.

Regular expressions
Note that wildcard patterns are not regular expressions, although they are a bit similar. First of all, they match filenames, rather than text, and secondly, the conventions are not the same: for example, in a regular expression '*' means zero or more copies of the preceding thing.

Now that regular expressions have bracket expressions where the negation is indicated by a '^', POSIX has declared the effect of a wildcard pattern "[^...]" to be undefined.

Se você quiser usar o ls, você deve ter em mente que o bash não irá traduzir o seu '*' da mesma forma que find -regexp ou grep . * [A-Z] * tentará corresponder a qualquer string seguida por letra maiúscula seguida por qualquer string, basicamente qualquer string.

    
por 29.08.2017 / 14:57
0

Quando você usa um padrão globbing de nome de arquivo na linha de comando, não apenas com ls , é o shell que o expande para qualquer nome correspondente, não o comando.

Isso significa que ls *[A-Z]* não está apenas usando ls , mas também usando o shell, que faz a expansão real do nome do arquivo.

Para usar somente o um comando para encontrar todos os nomes no diretório atual que consiste unicamente em caracteres ASCII maiúsculos, você teria que recorrer a find (GNU find usado aqui):

$ find . -maxdepth 1 -regex '^\./[A-Z]*$' -print

Altere -print para -ls para uma lista semelhante a ls -l .

Não existe padrão globbing de shell padrão que possa ser usado para encontrar nomes de arquivos com somente caracteres maiúsculos, embora bash (que eu assumo é o que você está usando ) tem extensões para esses padrões para alguns que podem, como você pode ver em algumas das outras respostas. Essas extensões vêm originalmente do AT & T ksh shell.

O padrão que você está usando aqui, *[A-Z]* , será expandido para todos os nomes que consistirem em pelo menos um caractere maiúsculo .

    
por 29.08.2017 / 15:28