Padrão de bash para corresponder a todos os arquivos, exceto diretórios

5

No bash, como especifico um padrão que corresponda a tudo, exceto subdiretórios no diretório atual. Dado que o padrão */ corresponde a todos os subdiretórios, eu tentei (com o extglob ativado):

$ echo !(*/)

Mas não funcionou.

    
por York 13.07.2014 / 21:53

5 respostas

6
find . -maxdepth 1 ! -type d

Detalhes:

  • -maxdepth 1 restringe a pesquisa ao diretório atual

  • ! -type d elimina diretórios

por 13.07.2014 / 22:22
6

O motivo */ corresponde aos diretórios é que o% final / restringe correspondências aos diretórios. Esse efeito só é acionado quando o / é após um padrão, você não pode usar / entre parênteses em !(*/) . Não há recurso embutido no bash para fazer o que você quer.

Você pode fazer um loop sobre todos os arquivos e construir um array.

non_directories=()
for x in *; do
  [ -d "$x" ] || non_directories+=("$x")
done
somecommand "${non_directories[@]}"

Você também pode usar find , se quiser executar um comando sobre todos os arquivos. Se sua implementação find o suportar (GNU, BSD, BusyBox), use -mindepth e -maxdepth para listar apenas as entradas nos diretórios atuais (com ./ prefixado). Use ! -name '.*' para omitir arquivos de ponto (se você quiser omiti-los).

find . -mindepth 1 -maxdepth 1 ! -type d -exec somecommand {} +

Se você só puder assumir um POSIX find , use -prune para evitar a recursão.

find . -name . -o -type d -prune -o -exec somecommand {} +

Se você quiser armazenar a saída de find em uma variável de matriz, tome cuidado, pois a análise da saída de find exige suposições adicionais no nome do arquivo. Você está melhor com um loop.

Em zsh, você pode usar qualificadores : *(^/) ou *(.) para corresponder apenas a arquivos regulares.

    
por 13.07.2014 / 22:49
3

Meio longo, mas:

for f in *; do if [ ! -d "$f" ]; then echo "$f"; fi; done

-d é um operador de teste de arquivo para verificar se o argumento é um diretório.

O texto acima também pode ser encurtado para

for f in *; do [ ! -d "$f" ] && echo "$f"; done
    
por 13.07.2014 / 22:01
2

Minha sugestão:

GLOBIGNORE=$(echo */)            # create list of directories with globbing
GLOBIGNORE=${GLOBIGNORE//:/\:}  # escape possible ":" with "\" to allow
                                 # the separator ":" in directory names
GLOBIGNORE=${GLOBIGNORE//\/ /:}  # replace "/ " with separator ":" 
GLOBIGNORE=${GLOBIGNORE%/}       # remove trailing "/"
ls -ld *

Resultado: nenhum diretório

Voltar para o padrão com unset GLOBIGNORE

    
por 14.07.2014 / 00:34
2

Não tenho certeza de qual das duas opções deseja alcançar - bash globing que exclui com base nos atributos do sistema de arquivos ou uma maneira de exibir apenas arquivos em um diretório?

Se o primeiro, não tenho certeza de que isso é possível. Globing apenas se expande, e nomes de arquivos são uma base em qualquer diretório - bash não distingue entre um nome de arquivo ou um nome de diretório por conta própria.

Se o segundo - você já tem 2 respostas, outra usando ls:

ls -dF * | grep -v "/$"  
    
por 13.07.2014 / 23:06