Como listar arquivos sem diretórios e filtrar por nome (opções ls)

42

Eu tenho um diretório chamado uploads. Ele contém vários arquivos, além de alguns subdiretórios que, por sua vez, contêm arquivos.

Existe uma maneira de eu (em uma etapa) fazer o seguinte:

  1. Listar APENAS os arquivos no diretório de uploads raiz - não quero ver os nomes das subpastas nem seu conteúdo;

    e

  2. NÃO liste nenhum arquivo que comece com t_

Eu sei sobre a -dbandeira, mas não me dá exatamente o que eu quero.

EmmyS
fonte

Respostas:

53

Isso parece um trabalho para find.

  • Use -maxdepthpara retornar apenas o diretório atual, e não procurar recursivamente dentro de subpastas
  • Use -type fpara retornar apenas arquivos e não diretórios ou nós de dispositivos ou qualquer outra coisa
  • Use uma combinação se -note -namepara evitar os arquivos com nomes que você não deseja

Pode vir assim:

find /path/to/uploads -maxdepth 1 -type f -not -name 't_*'
Caleb
fonte
Obrigado! Eu sou muito novo para CLI e nunca tinha usado encontrar antes. Definitivamente vou investigar melhor.
Emmys
2
@ EmmyS: Você pode encontrar mais um pequeno truque útil aqui. @Gilles mencionou usar -exec ls -lG -- {} +em sua resposta para obter a saída usando opções extras para ls. Você também pode adicionar apenas um -lsa essa descoberta para obter uma aproximação rápida e suja da visualização detalhada de ls.
Caleb
18

O GNU ls (ou seja, o comando ls em sistemas Linux não incorporados e o Cygwin, também disponível em outros órgãos) tem uma opção para ocultar alguns arquivos, com base em seus nomes. Porém, não há como ignorar diretórios.

ls --hide='t_*' uploads

Outra abordagem é fazer com que seu shell faça a correspondência. Bash, ksh e zsh têm um padrão de negação !(t_*)para corresponder a todos os arquivos, exceto aqueles correspondentes t*; No bash, esse recurso precisa ser ativado shopt -s extglobe, no zsh, precisa ser ativado setopt ksh_glob. O Zsh também possui a sintaxe equivalente ^t_*que precisa ser ativada setopt extended_glob. Isso ainda não ignora os diretórios. O Zsh possui um recurso extra que permite corresponder arquivos não apenas pelo nome, mas também por metadados e mais: qualificadores glob . Adicione (.)no final de uma correspondência para restringir a arquivos regulares. A negação ^faz parte da sintaxe de correspondência de nome, portanto, ^t_*(.)significa "todos os arquivos regulares que não correspondem t_*" e "não todos os arquivos que não correspondem aos arquivos regulares t_*".

setopt extended_glob  # put this in your ~/.zshrc
ls uploads/^t_*(.)

Se você se encontrar sem ferramentas avançadas, poderá fazer isso em qualquer unix com find. Não é o tipo de coisa que você normalmente digita na linha de comando, mas é poderoso e preciso. Caleb já mostrou como fazer isso com o GNU find . A -maxdepthopção não é portátil; você pode usar -prune, em vez disso, para parar findde recorrer com portabilidade.

find uploads/* -type d -prune -o \! -type f -name 't_*' -print

Substitua -printpor -exec ls -lG -- {} +para executar lscom suas opções favoritas nos arquivos.

Todos os comandos acima ocultam arquivos de ponto (ou seja, arquivos cujo nome começa com a .). Se você deseja exibi-los, passe -Apara lsou adicione o Dqualificador glob em zsh ( ls uploads/^t_*(.D)). Com find, você pode usar uma abordagem diferente para fazer com que ela recorra apenas um nível ( findnão trata especialmente os arquivos de ponto). Isso só funciona totalmente se você executar findno diretório atual.

cd uploads && find . -name . -o -type d -prune -o \! -type f -name 't_*' -print
Gilles 'SO- parar de ser mau'
fonte
3
Você tem um dia de trabalho? ;-) Estou constantemente impressionado com a extensão e o nível de detalhes de suas respostas, mesmo com as perguntas mais simples aqui no Unix SE! .. Continue assim mesmo! :)
alex
Obrigado! Grande detalhe. Não sei se tenho "ferramentas avançadas" ou não no momento; Eu estou em um Mac no trabalho (embora o Linux em casa, então eu tenho certeza que isso virá a calhar em algum ponto.)
Emmys
@EmmyS: Para a sua caixa Linux, meu uso -maxdepthdeve funcionar, mas o problema de "portabilidade" a que Gilles se refere é que o BSD find(também encontrado no OSX, eu acho) é um animal um pouco diferente, então você pode precisar da resposta dele também. @Gilles: +1 para o truque zsh!
Caleb
1
@Gilles: Alguns comentários não tão interessantes sobre prunes me vêm à mente, mas eu deixarei para lá dizendo simplesmente que, quando estou mexendo em meus próprios sistemas, o número de vezes que o pensamento " esse comando funcionaria se eu estivesse em AIX, Solaris ou MINIX3 "está aproximadamente ... em espera ... Estou tendo dificuldade em ler um medidor ... a tela está congelada 0.00.
Caleb
2
O Gnu não lstem uma --use-telepathyopção? Essa é a maneira mais rápida de exibir apenas os arquivos que você deseja. Talvez não seja portátil.
dubiousjim
8
ls -l /folder | grep ^- | awk '{print $9}'
Krayher
fonte
O que há $9nesta declaração?
Emmys
3
@EmmyS Significa o nono campo / coluna da saída. Esta resposta está tentando analisar a lssaída .
jw013
print $ NF` seria mais melhor, IMO. $ NF significa número de campos, que seria 9 e é um uso comum no AWK como uma boa oportunidade para ensinar aos outros sobre $ NF.
Elijah Lynn
1
ls -l | grep -v ^d | grep name$
RICARDO MARMOLEJO GARCIA
fonte
O que tornaria essa solução (que requer vários comandos e canais) preferível find?
precisa saber é o seguinte
É conciso, fácil de ler e permanece com a convenção de comando ls. Acho mais fácil lembrar do que os argumentos do comando find. Para cada um deles e parabéns por opções!
Tkjef 01/12/19
0

Deixe-me dar uma chance usando lse tubos:

ls  -l --hide='t_*'  uploads/ | grep -v ^d | tr -s ' ' | cut -d ' ' -f 9

digamos que a última coluna é a 9ª.

Y0NG
fonte
1
E se houver arquivos com espaços?
Jordanm 17/10
0

Se um problema de portabilidade -maxdepth da find for um problema, você pode usar:

ls -l uploads/ | awk '/^-/ && $9 !~/^t_/ {print $9}'

Não sou especialista, mas acho que isso deve funcionar. Suponho que parece um pouco enigmático, mas se você fala mal, na verdade não é. $ NF pode ser usado em vez de $ 9. Você também pode fazer:

ls -l uploads/ | awk '/^-/' | awk '!/^t_/ {print $9}'

que faz a mesma coisa (mas talvez com menos eficiência do que o anterior ???).

Na verdade, depois de pensar nos outros posts, parece que

ls -l --hide=t_* uploads/ | awk '/^-/ {print $9}'

é uma maneira ainda mais curta e clara.

Alguém por favor me corrija se eu estiver errado. :-)

kkaszub
fonte
A análise lsgeralmente não é uma boa ideia . Seus truques do awk falharão com nomes de arquivos com espaços em branco, por exemplo.
Mat
@mat - Obrigado pela correção. Depois de ler o artigo que você (e jw013) apontou, vejo que ls não pode ser confiável para saída de nomes de arquivos corretos. Mesmo se eu fosse reescrever o código awk para imprimir tudo, de US $ 9 ao final da linha (para incluir espaços em branco), essa saída ls ainda pode estar incorreta. Isso é decepcionante e deve ser corrigido na IMO. Obrigado novamente.
kkaszub
0

Eu encontrei estas maneiras curtas:

ls -p uploads | grep -Ev '/'

ou

ls -pIt_* uploads | grep -v /
Radu Rădeanu
fonte
-1

Tente este alias e use-o:

alias l='ls -hLlF'
Granular
fonte
ls -hLlFmostra os subdiretórios e mostra os arquivos começando com t_. Então, como isso responde à pergunta?
Raphael Ahrens
Talvez eu tenha entendido mal a pergunta. ls -hLlF não mostrará os diretórios de destino dos diretórios vinculados.
Granular
Parece que sim. Mas você não leu as outras respostas para a pergunta?
Raphael Ahrens
-1

Mole-mole:

ls -l --hide 't_*' <absolute path to desired directory> | grep -v ^d

Escavador
fonte
(1) Essa resposta é tão fácil que já foi dada antes. (2) Por que você acredita que precisa especificar o caminho completo para o diretório?
Scott
@ Scott - esta é uma maneira muito rápida e simples de chegar à solução. O caminho completo foi especificado para tornar a resposta universal ...
Digger