Corresponde ao nome da letra da letra n com ls

1

Estou usando o comando ls no bash, tentando encontrar todos os arquivos ou diretório de tamanho n. Digamos que n = 5

Meu comando é:

ls ?????

Mas isso também inclui caracteres que não são letras, como período. Por exemplo, os seguintes arquivos corresponderiam:

ab.cd    
abd.c

Eu só quero corresponder arquivos com cinco letras ou números:

five1
five2    
five3

Mas não

abc.d    
ab.cd    
a.bcd

Como posso modificar meu comando?

Resposta encontrada:

ls [a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]

Eu encontrei a resposta, mas como posso tornar isso menos feio?

    
por Saad A 15.02.2016 / 21:25

7 respostas

9

Observe que não é ls que interpreta esses globs. Esses globs são expandidos pelo shell em uma lista de nomes de arquivos que são passados como argumentos para ls . Conchas diferentes têm diferentes capacidades de globbing. bash tem algumas extensões sobre globs padrão (emprestado de ksh88 e ativado com shopt -s extglob ), mas ainda é limitado em comparação com shells como zsh ou ksh93 .

com zsh :

setopt extendedglob
ls -d [[:alnum:]](#c5)

ksh93 :

ls -d {5}([[:alnum:]])

ou:

ls -d {5}(\w) # (\w includes underscore in addition to alnums)

ou, se você quiser usar expressões regulares estendidas:

ls -d ~(E)^[[:alnum:]]{5}$

Com bash ou outros shells POSIX que não possuem operadores globbing equivalentes, você precisa fazer:

ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]

Observe que [[:alnum:]] inclui qualquer caractere alfabético na localidade atual (não apenas alfabetos latinos e muito menos o inglês) e 0123456789 (e possivelmente outros tipos de dígitos). Se você quiser as letras no alfabeto Inglês, nomeie os caracteres individualmente:

c='[0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ]'
unset -v IFS
ls -d $c$c$c$c$c

Ou use o idioma C:

(export LC_ALL=C
ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]])
    
por 15.02.2016 / 23:33
5
ls -q | grep -Ex '[[:alnum:]]{5}'
    
por 15.02.2016 / 22:12
5

Se você vai usar ls da maneira que você mencionou, você deve usar a opção -d ; de outra forma, listará os conteúdos de quaisquer diretórios cujos nomes são cinco letras e / ou dígitos, em vez de listar os próprios nomes. Além disso, você pode fazer

ls -d [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]

mas é exatamente a mesma digitação que a resposta que você tem agora.

Além disso, se você não precisar usar ls no seu comando, você pode usar

echo [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]

que listará todas as correspondências em uma linha ou

printf "%s\n" [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][:alnum:]]

, que irá listá-los em linhas separadas.

    
por 15.02.2016 / 23:33
4

Eu não sei se você vai contar isso como "menos feio", mas você pode usar o GNU find da seguinte forma:

 find -maxdepth 1 -regextype posix-extended -regex './[[:alnum:]]{5}'

embora isso coloque ./ na frente de cada entrada, embora você possa sed ausente

Dependendo do que você faz a seguir, find também pode ter a vantagem de ajudar a evitar problemas de análise de problemas

Mantendo-o com extglobs ( shopt -s extglob ) você pode reescrevê-lo um pouco, embora eu não saiba se você o considera limpo

ls [[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]][[:alnum:]]
    
por 15.02.2016 / 21:53
2

Construa a expressão em uma variável:

 e=""; for m in $(seq 1 5); do e="$e[A-Za-z0-9]"; done

Coloque em uma função para ser fantasia / reutilizável:

 alnumglob() {
    local e=""
    for m in $(seq 1 $1) ; do e="$e[A-Za-z0-9]"; done
    echo "$e"
 }

 ls -ld $(alnumglob 5)
    
por 15.02.2016 / 23:55
1

Se você quiser determinar com segurança o tamanho de uma string com bash , você deve usar expansão do parâmetro . ls sozinho só é capaz de sintaxe glob, que (provavelmente) não pode fazer o que você quer. find tem implementações diferentes no BSD e alguns Linuxes e -regextype não são necessariamente um sinalizador legal. A boa notícia é que o bash tem loops e estes podem dar o que você quer.

for filename in *              # globs all files in your directory.
do
    clip=${filename%.*}        # excludes the first extension
    if [[ ${#clip} -eq 5 ]]    # test the length of the remaining string
    then
        ls -d $filename        # call ls to show you the file or directory
    fi
done

Se, em vez disso, você precisar de qualquer nome de arquivo somente com cinco caracteres alfanuméricos, seu método e outras respostas só retornarão os arquivos que iniciam com cinco caracteres. Por exemplo:

Usando ls [a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9][a-zA-Z0-9]

five1.txt      # matches
fi_ve.txt      # fails
a.pages        # fails
q_fiver.txt    # fails

Para incluir qualquer arquivo com qualquer cadeia alfanumérica de cinco caracteres e somente aqueles com qualquer cadeia alfanumérica de cinco caracteres, você pode usar a implementação de regex mais universal de grep no bash. Embora eu normalmente não o recomendasse, o uso de \w e \W aqui pode ajudar muito a legibilidade (onde \w = [[:alnum:]] e \W = [^[:alnum:]] - mas eles incluirão sublinhados , então use em perigo).

for filename in *
do
    if (grep -qE '(^|\W)\w{5}($|\W)' <<<"$filename")
    then
        ls -d "$filename"
    fi
done
    
por 16.02.2016 / 10:55
0

Se tudo o que você quer é torná-lo menos feio, você pode alterar [a-zA-Z0-9] para [[:alnum:]] , atribuir isso a uma variável:

a='[[:alnum:]]'

E use cinco vezes:

$ ls $a$a$a$a$a             ### important that the vars are not quoted.  
five1 five2 five3
    
por 16.02.2016 / 07:10

Tags