2011-10-31 03:47:31 +0000 2011-10-31 03:47:31 +0000
106
106

Bash scripting: teste para directório vazio

Quero testar se um directório não contém quaisquer ficheiros. Se assim for, vou saltar algum processamento.

Eu tentei o seguinte:

if [./* == "./*"]; then
    echo "No new file"
    exit 1
fi

Isso dá o seguinte erro:

line 1: [: too many arguments

Existe uma solução/alternativa?

Respostas (18)

135
135
135
2011-10-31 03:53:28 +0000
if [-z "$(ls -A /path/to/dir)"]; then
   echo "Empty"
else
   echo "Not Empty"
fi

Além disso, seria fixe verificar se o directório existe antes.

24
24
24
2013-10-29 21:07:29 +0000

Não há necessidade de contar nada ou globos de concha. Também pode usar read em combinação com find. Se a saída do find estiver vazia, devolverá false:

if find /some/dir -mindepth 1 | read; then
   echo "dir not empty"
else
   echo "dir empty"
fi

Isto deve ser portátil.

20
20
20
2011-10-31 10:53:57 +0000
if [-n "$(find "$DIR_TO_CHECK" -maxdepth 0 -type d -empty 2>/dev/null)"]; then
    echo "Empty directory"
else
    echo "Not empty or NOT a directory"
fi
14
14
14
2011-11-01 14:51:09 +0000
#!/bin/bash
if [-d /path/to/dir]; then
    # the directory exists
    ["$(ls -A /path/to/dir)"] && echo "Not Empty" || echo "Empty"
else
    # You could check here if /path/to/dir is a file with [-f /path/to/dir]
fi
4
4
4
2018-09-26 13:50:40 +0000

Com FIND(1) (sob Linux e FreeBSD) pode olhar não recursivamente para uma entrada de directório via “-maxdepth 0” e testar se está vazio com “-empty”. Aplicado à questão que isto dá:

if test -n "$(find ./ -maxdepth 0 -empty)" ; then
    echo "No new file"
    exit 1
fi
4
4
4
2014-10-24 01:23:28 +0000

Uma forma hacky, mas sem PID:

is_empty() {
    test -e "$1/"* 2>/dev/null
    case $? in
        1) return 0 ;;
        *) return 1 ;;
    esac
}

Isto tira partido do facto de test construir saídas com 2 se for dado mais do que um argumento depois de -e: Primeiro, "$1"/* glob é expandido por bash. Isto resulta em um argumento por ficheiro. Assim

  • Se não houver ficheiros, o asterisco em test -e "$1"* não se expande, por isso a Shell volta a tentar o ficheiro *, que retorna 1.

& - …excepto se houver realmente um ficheiro com o nome exacto *, então o asterisco expande-se bem, asterisco, que acaba por ser a mesma chamada que acima, ou seja, test -e "dir/*", só que desta vez retorna 0. (Obrigado @TrueY por apontar isto. )

& - Se houver um ficheiro, test -e "dir/file" é executado, que retorna 0.

  • Mas se houver mais ficheiros do que 1, test -e "dir/file1" "dir/file2" é executado, o que o bash reporta como erro de utilização, ou seja, 2.

case envolve toda a lógica de modo a que apenas o primeiro caso, com 1 estado de saída, seja reportado como sucesso.

Possíveis problemas que ainda não verifiquei:

  • Há mais ficheiros do que o número de argumentos permitidos - acho que isto poderia comportar-se de forma semelhante ao caso com 2+ ficheiros.

  • Ou há de facto um ficheiro com um nome vazio - Não tenho a certeza se é possível em qualquer OS/FS sãos.

4
4
4
2011-10-31 10:06:28 +0000

Isto fará o trabalho no directório de trabalho actual (.):

[`ls -1A . | wc -l` -eq 0] && echo "Current dir is empty." || echo "Current dir has files (or hidden files) in it."

ou o mesmo comando dividido em três linhas apenas para ser mais legível:

[`ls -1A . | wc -l` -eq 0] && \
echo "Current dir is empty." || \
echo "Current dir has files (or hidden files) in it."

Basta substituir ls -1A . | wc -l por ls -1A <target-directory> | wc -l se for necessário executá-lo numa pasta de destino diferente.

Editar : Substitui -1a por -1A (ver comentário @Daniel)

3
3
3
2011-10-31 10:17:15 +0000

Use o seguinte:

count="$( find /path -mindepth 1 -maxdepth 1 | wc -l )"
if [$count -eq 0] ; then
   echo "No new file"
   exit 1
fi

Desta forma, é independente do formato de saída de ls. -mindepth salta o próprio directório, -maxdepth previne a defesa recorrente em subdirectórios para acelerar as coisas.

3
3
3
2014-08-12 21:46:08 +0000

Usando uma matriz:

files=( * .* )
if (( ${#files[@]} == 2 )); then
    # contents of files array is (. ..)
    echo dir is empty
fi
2
2
2
2018-06-20 09:17:01 +0000

E que tal testar se o directório existe e não vazio num se a declaração

if [[-d path/to/dir && -n "$(ls -A path/to/dir)"]]; then 
  echo "directory exists"
else
  echo "directory doesn't exist"
fi
1
1
1
2013-10-29 20:57:27 +0000

Penso que a melhor solução é:

files=$(shopt -s nullglob; shopt -s dotglob; echo /MYPATH/*)
[["$files"]] || echo "dir empty"

graças a https://stackoverflow.com/a/91558/520567

Esta é uma edição anónima da minha resposta que pode ou não ser útil a alguém: Uma ligeira alteração dá o número de ficheiros:

files=$(shopt -s nullglob dotglob; s=(MYPATH/*); echo ${s[*]}) 
echo "MYPATH contains $files files"

Isto funcionará correctamente mesmo que os nomes dos ficheiros contenham espaços.

1
1
1
2020-02-16 18:53:46 +0000

A pergunta era:

if [./* == "./*"]; then
    echo "No new file"
    exit 1
fi

Resposta é:

if ls -1qA . | grep -q .
    then ! exit 1
    else : # Dir is empty
fi
1
1
1
2018-05-25 17:06:53 +0000
if find "${DIR}" -prune ! -empty -exit 1; then
    echo Empty
else
    echo Not Empty
fi

EDIT: Penso que esta solução funciona bem com o gnu find, depois de um quick* olhar para a implementação . Mas isto pode não funcionar, por exemplo, com netbsd’s find . De facto, este utiliza o campo de tamanho stat(2). O manual descreve-o como:

st_size The size of the file in bytes. The meaning of the size
                   reported for a directory is file system dependent.
                   Some file systems (e.g. FFS) return the total size used
                   for the directory metadata, possibly including free
                   slots; others (notably ZFS) return the number of
                   entries in the directory. Some may also return other
                   things or always report zero.

Uma solução melhor, também mais simples, é:

if find "${DIR}" -mindepth 1 -exit 1; then
    echo Empty
else
    echo Not Empty
fi

Além disso, a -pruna na 1ª solução é inútil.

EDIT: no -exit for gnu find… a solução acima é boa para a descoberta do NetBSD. Para o achado GNU, isto deve funcionar:

if [-z "`find \"${DIR}\" -mindepth 1 -exec echo notempty \; -quit`"]; then
    echo Empty
else
    echo Not Empty
fi
0
0
0
2020-01-15 17:46:01 +0000

Eu fiz esta abordagem:

CHECKEMPTYFOLDER=$(test -z "$(ls -A /path/to/dir)"; echo $?)
if [$CHECKEMPTYFOLDER -eq 0]
then
  echo "Empty"
elif [$CHECKEMPTYFOLDER -eq 1]
then
  echo "Not Empty"
else
  echo "Error"
fi
0
0
0
2018-05-02 13:29:51 +0000

Este trabalho para mim, para verificar & processar ficheiros no directório ../IN, considerando que o guião está no directório ../Script:

FileTotalCount=0

    for file in ../IN/*; do
    FileTotalCount=`expr $FileTotalCount + 1`
done

if test "$file" = "../IN/*"
then

    echo "EXITING: NO files available for processing in ../IN directory. "
    exit

else

  echo "Starting Process: Found ""$FileTotalCount"" files in ../IN directory for processing."

# Rest of the Code
0
0
0
2012-02-24 10:06:37 +0000

Tudo isto é óptimo - apenas o transformei num guião para que eu possa verificar directórios vazios abaixo do actual. O abaixo deve ser colocado num ficheiro chamado ‘findempty’, colocado no caminho algures para que o bash o possa encontrar e depois chmod 755 para correr. Pode ser facilmente alterado de acordo com as suas necessidades específicas, suponho.

#!/bin/bash
if ["$#" == "0"]; then 
find . -maxdepth 1 -type d -exec findempty "{}" \;
exit
fi

COUNT=`ls -1A "$*" | wc -l`
if ["$COUNT" == "0"]; then 
echo "$* : $COUNT"
fi
-1
-1
-1
2018-01-10 17:12:56 +0000

Para qualquer directório que não seja o actual, pode verificar se está vazio, tentando rmdir, porque rmdir é garantido falhar para directórios não vazios. Se o rmdir for bem sucedido, e se realmente quisesse que o directório vazio sobrevivesse ao teste, apenas mkdir novamente.

Não utilize este hack se houver outros processos que possam ser descombatidos por um directório que eles saibam que brevemente deixarão de existir.

Se rmdir não funcionar para si, e se estiver a testar directórios que possam potencialmente conter um grande número de ficheiros, qualquer solução que se baseie em shell globbing poderá ficar lenta e/ou entrar em limites de comprimento de linha de comando. Provavelmente, será melhor usar find nesse caso. A solução find mais rápida de que me consigo lembrar é como

is_empty() {
    test -z $(find "$1" -mindepth 1 -printf X -quit)
}

Isto funciona para as versões GNU e BSD de find mas não para a versão Solaris, que está a faltar cada um desses operadores find. Adoro o seu trabalho, Oracle.

-3
-3
-3
2018-04-08 20:54:13 +0000

Pode tentar remover o directório e esperar por um erro; rmdir* não apagará o directório se este não estiver vazio.

_path="some/path"
if rmdir $_path >/dev/null 2>&1; then
   mkdir $_path # create it again
   echo "Empty"
else
   echo "Not empty or doesn't exist"
fi