Verifique em ksh se um diretório está vazio

3

Como posso verificar se um diretório está vazio ou não em ksh no AIX?

Se houver arquivos, só preciso remover arquivos.

    
por Aravind 10.02.2015 / 14:56

6 respostas

2

Aqui está uma maneira compatível com POSIX de testar se dir está vazio usando apenas construções de shell internas. O comando set define os argumentos posicionais para arquivos de ponto (incluindo os sempre existentes . e .. ) seguidos por arquivos sem ponto. Se o diretório estiver vazio, o .* glob corresponderá apenas a . e .. , e o * glob não corresponderá a nada, portanto, não será expandido.

set dir/.* dir/*
[ "$1" = "dir/." ] && [ "$2" = "dir/.." ] && ! [ -e "$3" ] && ! [ -L "$3" ]

Isso funciona no ATT ksh, mas falha com alguns shells que omitem as entradas . e .. . Para ser mais portável, você também precisa permitir que .* não corresponda a nada.

set dir/.* dir/*
case $# in
  0) true;; # can't happen in a standard shell, this is for shells with nullglob
  2) { [ "$1" = "dir/.*" ] && [ "$2" = "dir/*" ] && ! [ -e "$1" ] && ! [ -L "$1" ] && ! [ -e "$2" ] && ! [ -L "$2" ]; } ||
     { [ "$1" = "dir/." ] && [ "$2" = "dir/.." ]; };;
  3) [ "$1" = "dir/." ] && [ "$2" = "dir/.." ] && ! [ -e "$3" ] && ! [ -L "$3" ];;
  *) false;;
esac

Versões recentes suficientes do ksh permitem um teste mais simples, mas acho que o AIX é muito antigo (mesmo o ksh93 ). Veja como você pode testar se dir está vazio em um ksh93 recente:

FIGNORE='.?(.)'; set -- ~(N)dir/*; [[ $# -eq 0 ]]

ou alternativamente

FIGNORE=; set -- dir/*; [[ $# -eq 2 ]]

Uma abordagem alternativa é chamar find . Isso é mais simples porque find não trata os arquivos pontuais especialmente e não tem nada parecido com a dificuldade do shell em distinguir entre um padrão que combina com um único arquivo e um padrão que não foi expandido porque não combina com nada. >

[ -z "$(find dir/. -name . -o -print | head -n 1)" ]
    
por 11.02.2015 / 00:30
0

Em qualquer shell [ "$(find path_to_dir -mindepth 1)" ] || echo EMPTY

    
por 10.02.2015 / 15:09
0

Não conheço nenhum caminho direto, e também depende se você quer também que os arquivos de ponto sejam considerados. Isso (ou uma variação disso) pode fazer o que você quiser ...

set directory/*
[[ -f $1 ]] || print empty
    
por 10.02.2015 / 15:09
0

Você pode deixar as globs se resolverem. Tanto quanto eu saiba, esta estratégia deve ser muito portável para todos os casos exceto em que você tenha permissões de leitura para dir/ , mas apenas permissões de pesquisa para dir/../ . Isso ocorre porque as permissões de leitura e pesquisa são necessárias para resolver uma glob, mas apenas as permissões de pesquisa para exibir uma correspondência.

set di[r]/* di[r]/.[!.]* di[r]/..?*
case $* in 
(*r/*) echo dir not empty;;
(*]/*) echo dir is empty ;;
esac

Isso funciona porque, se um nome de caminho for resolvido para qualquer um dos três globs - que não correspondem a dir/. ou dir/.. -, então o di [r] glob também deve ser resolvido, mas os resultados não podem expandir / . As opções acima devem funcionar com qualquer posh , ksh , bash , dash , mksh , yash , mksh ou busybox ash . Ele também funcionará para zsh se emulate sh estiver definido. O seguinte também funciona para a maioria deles - todos, exceto posh e mksh , até onde eu sei - e deve funcionar para todos os shells POSIX:

Para o diretório atual, você pode fazer:

set "/./${PWD##*/}/"
set "$1" .?"$1"* .?"$1".[!.]* .?"$1"..?*
case $* in (*.././*) set "$1";;esac
printf "%s%${2+.}3sempty\n" "${1#/} " "is not "

... que não tem o problema de permissão de leitura / pesquisa porque todos os globs são resolvidos para o diretório atual - embora eles recurse. Aqui está outra vez, um pouco:

ksh -x <<\SCRIPT  
dirempty(){
    cd -P -- "${1-.}" && set "/./${PWD##*/}/" || return 2
    set .?"$1"* .?"$1".[!.]* .?"$1"..?*
    case $* in (*.././*) set --;;esac
    printf "%s%${1+.}2s empty\n" "$PWD " "is not"
    cd -- "$OLDPWD" && return "$((!$#))"
}

###TEST LOOP###

    mkdir empty
    for new in "" ... notdot
    do  for c in touch mkdir
        do  "$c" "empty/$new" 2>&3
            dirempty empty ||
            rm -rf "empty/$new"
        done 
    done 3>/dev/null

###END
SCRIPT

Veja alguns dos set -x output:

+ touch empty/
+ dirempty empty
+ cd -P -- empty
+ set /./empty/
+ set '.?/./empty/*' '.?/./empty/.[!.]*' '.?/./empty/..?*'
+ printf '%s%.2s empty\n' '/home/mikeserv/empty/ ' 'is not'
/home/mikeserv/empty/ is empty
+ cd -- /home/mikeserv
+ return 0

É a seguinte linha que demonstra como funciona melhor:

... '.?/./empty/*' '.?/./empty/.[!.]*' '.?/./empty/..?*' ...

... porque, para cada um dos * , .[!.]* e ..?* , o nome do caminho todo é inválido, então também cada parte é não globs resolve - para incluir o primeiro .? . Compare isso com essa outra seção da mesma saída ...

+ touch empty/...
...
+ set /./empty/
+ set '.?/./empty/*' '.?/./empty/.[!.]*' .././empty/...
+ set --
+ printf '%s%2s empty\n' '/home/mikeserv/empty/ ' 'is not'
/home/mikeserv/empty/ is not empty
+ cd -- /home/mikeserv
+ return 1

Veja ...

'.?/./empty/*' '.?/./empty/.[!.]*' .././empty/...

... porque ..?* resolve, então também .?/./ , então tudo que é necessário é procurar uma ocorrência de .././ na matriz da shell e é tratado como:

case $* in (*.././*)

E é assim que você pode simplesmente checar se um glob resolve (e assim também confiantemente verificar qualquer conteúdo do diretório) - apenas compare o desconhecido com o conhecido.

    
por 11.02.2015 / 11:47
0

Aqui está uma função que funciona em muitos Unixes,

em shells compatíveis com Bourne (mesmo modelos pré-históricos),

e não perfura muito fundo (o sistema de arquivos, a CPU e o cérebro):

isempty() { [ -z "'find \"$1/.\" ! -name . -print -prune | head -1'" ] ; }
    
por 21.03.2016 / 16:40
0

Eu poderia ter supervisionado algo, mas isso deve funcionar também e é IMHO mais legível do que definir ou encontrar.

-A apenas exclui . e .. , mas inclui outros dotfiles.

| head -n 5 é para encurtar o ls no caso de muitos arquivos. Você pode omiti-lo se espera ter nenhum ou poucos arquivos nas pastas que está verificando. Editar : atualizei para 5, por isso, lidamos com um nome de arquivo sneeky que começa com nova (s) linha (s).

if [ -z "$(ls -A /path/to/folder | head -n 5)" ] 
then 
    print "EMPTY"
else 
    print "NOT EMPTY"
fi

Verificado no AIX 7.1

    
por 26.05.2016 / 17:12

Tags