Em um script de shell, como verifico se um diretório contém arquivos?
Algo parecido com isso
if [ -e /some/dir/* ]; then echo "huzzah"; fi;
mas que funciona se o diretório contém um ou vários arquivos (o acima só funciona com exatamente 0 ou 1 arquivo).
Respostas:
As soluções até agora usam
ls
. Esta é uma solução totalmente bash:fonte
shopt -q nullglob || resetnullglob=1; shopt -s nullglob; shopt -q dotglob || resetdotglob=1; shopt -s dotglob; files=(/some/dir/*); [ "$files" ] && echo "wowzers"; [ "$resetdotglob" ] && shopt -u dotglob; [ "$resetnullglob" ] && shopt -u nullglob;
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
files=$(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*)
então a instrução if deve mudar paraif [ ${#files} -gt 0 ];
ou talvez você apenas tenha esquecido o () ao redor do comando do sub-shell?files=($(shopt -s nullglob;shopt -s dotglob;echo /some/dir/*))
Três melhores truques
shopt -s nullglob dotglob; f=your/dir/*; ((${#f}))
Este truque é 100%
bash
e invoca (gera) um sub-shell. A ideia é de Bruno De Fraine e melhorada pelo comentário do teambob .Nota: não há diferença entre um diretório vazio e um não existente (e mesmo quando o caminho fornecido é um arquivo).
Há uma alternativa semelhante e mais detalhes (e mais exemplos) no FAQ 'oficial' do canal de IRC #bash :
[ -n "$(ls -A your/dir)" ]
Este truque é inspirado no artigo da nixCraft postado em 2007. Adicione
2>/dev/null
para suprimir o erro de saída"No such file or directory"
.Veja também a resposta de Andrew Taylor (2008) e a resposta de gr8can8dian (2011).
ou a versão do bashismo de uma linha:
Nota:
ls
retorna$?=2
quando o diretório não existe. Mas não há diferença entre um arquivo e um diretório vazio.[ -n "$(find your/dir -prune -empty)" ]
Este último truque é inspirado na resposta da gravstar, onde
-maxdepth 0
é substituído-prune
e melhorado pelo comentário de phils .uma variação usando
-type d
:Explicação:
find -prune
é semelhante afind -maxdepth 0
usar menos caracteresfind -empty
imprime os diretórios e arquivos vaziosfind -type d
imprime diretórios apenasObservação: você também pode substituir
[ -n "$(find your/dir -prune -empty)" ]
apenas pela versão abreviada abaixo:Este último código funciona na maioria dos casos, mas esteja ciente de que caminhos maliciosos podem expressar um comando ...
fonte
[ -n "$(find "your/dir" -prune -empty)" ]
, para evitar a repetição do caminho do diretório.if [ ``ls -A your/dir`` ]
em um script, cheguei à conclusão de que funciona bem para um diretório com 0, 1 ou 2 subdiretórios, mas falha para um diretório com mais de 2 subdiretórios.line 17: [: 20150424-002813: unary operator expected
onde20150424-002813
estava um dos nomes de diretório. A concha usada era/bin/bash/
. Eu finalmente mudei parals "$destination" | tail -1
if [ ``ls -A my/dir`` ]
sai por enganobash: [: -A: binary operator expected
. Testado nas versões 4.1.2 e 4.2.53 do bash.-n
variante estava no título, mas não no parágrafo abaixo). Então, sim, está bem.ls: cannot access '/path': No such file or directory
. Existe uma maneira de suprimir esta mensagem? Eu gostaria de falhar silenciosamente lá.Que tal o seguinte:
Desta forma, não há necessidade de gerar uma listagem completa do conteúdo do diretório. O
read
serve para descartar a saída e fazer com que a expressão seja avaliada como verdadeira apenas quando algo for lido (ou seja,/some/dir/
for encontrado vazio porfind
).fonte
find /some/dir/ -maxdepth 0 -empty -exec echo "huzzah" \;
ls
saída e não depende de recursos de shell não padrão.-maxdepth
e dos-empty
primários.Experimentar:
fonte
/bin/ls <some_dir>/* 2> /dev/null
if [! -z "$ tmp"]; então echo Something is there fils /some/dir/*
]; então echo "huzzah"; fi-n
vez de! -z
(ambos são equivalentes, mas por que não usar a forma mais curta quando existe).BigGray% if [ ! -z
ls / some / dir / * `]; então echo "huzzah"; fi zsh: nenhuma correspondência encontrada: / some / dir / * `ls...
em bashfonte
Cuidado com os diretórios com muitos arquivos! Pode levar algum tempo para avaliar o
ls
comando.IMO a melhor solução é aquela que usa
fonte
fonte
Você poderia comparar a saída disso?
fonte
Algumas notas de implementação:
for
loop evita uma chamada para umls
processo externo . Ele ainda lê todas as entradas do diretório uma vez. Isso só pode ser otimizado escrevendo um programa C que usa readdir () explicitamente.test -e
dentro do loop captura o caso de um diretório vazio, caso em que a variável_ief
seria atribuída ao valor "somedir / *". Somente se o arquivo existir a função retornará "não vazio"test
implementação não suporta a-e
bandeira.fonte
dotglob
não for definido -shopt -s dotglob
Isso me diz se o diretório está vazio ou não, o número de arquivos que ele contém.
fonte
ls
.Esta pode ser uma resposta muito tardia, mas aqui está uma solução que funciona. Esta linha reconhece apenas a existência de arquivos! Ele não fornecerá um falso positivo se houver diretórios.
fonte
Suponha que você não tenha um arquivo nomeado
*
em/any/dir/you/check
, ele deve funcionarbash
dash
posh
busybox sh
e,zsh
mas (para zsh) exigirunsetopt nomatch
.Os desempenhos devem ser comparáveis a qualquer um
ls
que use*
(glob), acho que será lento em diretórios com muitos nós (meu/usr/bin
com mais de 3000 arquivos não foi tão lento), usará pelo menos memória suficiente para alocar todos os diretórios / nomes de arquivos (e mais) como todos eles são passados (resolvidos) para a função como argumentos, alguns shell provavelmente têm limites no número de argumentos e / ou comprimento dos argumentos.Seria bom ter uma maneira rápida e portátil O (1) de zero recursos para verificar se um diretório está vazio.
atualizar
A versão acima não leva em conta arquivos / diretórios ocultos, caso seja necessário mais algum teste, como os truques sh (shell POSIX)
is_empty
de Rich :Mas, em vez disso, estou pensando em algo assim:
Alguma preocupação sobre as diferenças de barras finais do argumento e da saída de encontrar quando o dir está vazio, e novas linhas finais (mas isso deve ser fácil de manusear), infelizmente no meu
busybox
sh
programa o que provavelmente é um bug nofind -> dd
tubo com a saída truncada aleatoriamente ( se useicat
a saída é sempre a mesma, parece serdd
com o argumentocount
).fonte
is_empty(){ [ ! -d "${1}" ] && return 2;set -- "${1}" "${1}"/* "${1}"/.[!.]* "${1}"/..?*;[ "${*}" = "${1} ${1}/* ${1}/.[!.]* ${1}/..?*" ]; };
ZSH
Eu sei que a pergunta foi marcada para bash; mas, apenas para referência, para usuários zsh :
Teste para diretório não vazio
Para verificar se
foo
não está vazio:onde, se
foo
não estiver vazio, o código dofor
bloco será executado.Teste para diretório vazio
Para verificar se
foo
está vazio:onde, se
foo
estiver vazio, o código dofor
bloco será executado.Notas
Não precisamos citar o diretório
foo
acima, mas podemos fazer isso se precisarmos:Também podemos testar mais de um objeto, mesmo que não seja um diretório:
Tudo o que não for um diretório será simplesmente ignorado.
Extras
Já que estamos globbing, podemos usar qualquer glob (ou expansão de chave):
Também podemos examinar objetos colocados em uma matriz. Com os diretórios acima, por exemplo:
Assim, podemos testar objetos que já podem estar configurados em um parâmetro de matriz.
Observe que o código no
for
bloco é, obviamente, executado em cada diretório por vez. Se isso não for desejável, você pode simplesmente preencher um parâmetro de matriz e, em seguida, operar nesse parâmetro:Explicação
Para usuários zsh, há o
(F)
qualificador glob (consulte Recursosman zshexpn
), que corresponde a diretórios "completos" (não vazios):O qualificador
(F)
lista os objetos que correspondem: é um diretório E não está vazio. Portanto,(^F)
corresponde a: não é um diretório OU está vazio. Assim,(^F)
sozinho também listaria arquivos regulares, por exemplo. Portanto, conforme explicado nazshexp
página do manual, também precisamos do(/)
qualificador glob, que lista apenas os diretórios:Assim, para verificar se um determinado diretório está vazio, você pode executar:
e apenas para ter certeza de que um diretório não vazio não seria capturado:
Ops! Como
Y
não está vazio, zsh não encontra correspondências para(/^F)
("diretórios que estão vazios") e, portanto, exibe uma mensagem de erro informando que nenhuma correspondência para o glob foi encontrada. Portanto, precisamos suprimir essas possíveis mensagens de erro com o(N)
qualificador glob:Assim, para diretórios vazios, precisamos do qualificador
(N/^F)
, que pode ser lido como: "não me avise sobre falhas, diretórios que não estão cheios".Da mesma forma, para diretórios não vazios, precisamos do qualificador
(NF)
, que também podemos ler como: "não me avise sobre falhas, diretórios completos".fonte
Estou surpreso que o guia complicado sobre diretórios vazios não tenha sido mencionado. Este guia, e realmente tudo de lã, é uma leitura obrigatória para perguntas do tipo shell.
Digno de nota nessa página:
fonte
Pequena variação da resposta de Bruno :
Funciona para mim
fonte
Pegando uma dica (ou várias) da resposta de olibre, gosto de uma função Bash:
Porque, embora crie um subshell, é o mais próximo de uma solução O (1) que posso imaginar e dar um nome a torna legível. Eu posso então escrever
Quanto a O (1), há casos atípicos: se um diretório grande teve todos ou todos, exceto a última entrada excluída, "find" pode ter que ler tudo para determinar se está vazio. Eu acredito que o desempenho esperado é O (1), mas o pior caso é linear no tamanho do diretório. Eu não medi isso.
fonte
Até agora não vi uma resposta que use grep, o que acho que daria uma resposta mais simples (sem muitos símbolos estranhos!) Aqui está como eu verificaria se existem arquivos no diretório usando o shell do bourne:
isso retorna o número de arquivos em um diretório:
você pode preencher o caminho do diretório onde o diretório está escrito. A primeira metade do pipe garante que o primeiro caractere de saída seja "-" para cada arquivo. egrep então conta o número de linhas que começam com aquele símbolo usando expressões regulares. agora tudo o que você precisa fazer é armazenar o número obtido e compará-lo usando crases como:
x é uma variável de sua escolha.
fonte
Misturando coisas de poda e últimas respostas, eu tenho que
que funciona para caminhos com espaços também
fonte
Resposta simples com bash :
fonte
Eu iria para
find
:Isso verifica a saída de procurar apenas arquivos no diretório, sem passar pelos subdiretórios. Em seguida, verifica a saída usando a
-z
opção retirada deman test
:Veja alguns resultados:
Dir vazio:
Apenas dirs nele:
Um arquivo no diretório:
Um arquivo em um subdiretório:
fonte
Com alguma solução alternativa, poderia encontrar uma maneira simples de descobrir se há arquivos em um diretório. Isso pode ser estendido com mais comandos grep para verificar especificamente arquivos .xml ou .txt, etc. Ex:
ls /some/dir | grep xml | wc -l | grep -w "0"
fonte
fonte
nullglob
, porque ols
comando será bem-sucedido.para testar um diretório de destino específico
fonte
Tente com o comando find. Especifique o diretório codificado ou como argumento. Em seguida, inicie a localização para pesquisar todos os arquivos dentro do diretório. Verifique se o retorno do find é nulo. Ecoar os dados de encontrar
fonte
Não gosto das
ls - A
soluções postadas. Provavelmente, você deseja testar se o diretório está vazio porque não deseja excluí-lo. O seguinte faz isso. Se, no entanto, você deseja apenas registrar um arquivo vazio, certamente excluí-lo e recriá-lo é mais rápido do que listar arquivos possivelmente infinitos.Isso deve funcionar ...
fonte
${target}/..
.Funciona bem para mim (quando existe dir):
Com verificação completa:
fonte