Eu tenho um requisito, se eu executar um script ./123
com argumentos de caminho vazio, diga /usr/share/linux-headers-3.16.0-34-generic/.tmp_versions
(este diretório está vazio). Ele deve exibir "o diretório está vazio"
Meu código é:
#!/bin/bash
dir="$1"
if [ $# -ne 1 ]
then
echo "please pass arguments"
exit
fi
if [ -e $dir ]
then
printf "minimum file size: %s\n\t%s\n" \
$(du $dir -hab | sort -n -r | tail -1)
printf "maximum file size: %s\n\t%s\n" \
$(du $dir -ab | sort -n | tail -1)
printf "average file size: %s"
du $dir -sk | awk '{s+=$1}END{print s/NR}'
else
echo " directory doesn't exists"
fi
if [ -d "ls -A $dir" ]
then
echo " directory is empty"
fi
Eu tenho um erro exibido como, se eu executar o nome do script ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
(este diretório está vazio).
minimum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
maximum file size: 4096
/usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
average file size: 4
em vez de mostrar apenas a saída "o diretório está vazio", mostra a saída acima
A saída abaixo deve ser exibida se eu exceder o script com argumentos corretos (quero dizer, com o caminho correto do diretório). dizer./123 /usr/share
minimum file size: 196
/usr/share
maximum file size: 14096
/usr/share
average file size: 4000
minha saída esperada é: ./123 /usr/src/linux-headers-3.16.0-34-generic/.tmp_versions
directory is empty.
shell-script
buddha sreekanth
fonte
fonte
Respostas:
O acima é um teste compatível com POSIX - e deve ser muito rápido.
ls
irá listar todos os arquivos / diretórios em um diretório excetuando.
e..
cada um por linha e-q
uote todos os caracteres não imprimíveis (para incluir\n
ewlines) na saída com um?
ponto de interrogação. Dessa maneira, segrep
receber um único caractere na entrada, ele retornará verdadeiro - caso contrário, falso.Para fazer isso apenas em um shell POSIX:
Um shell POSIX (que não desativou anteriormente a
-f
geração do nome do il) seráset
a"$@"
matriz do parâmetro posicional para as seqüências literais seguidas peloset
comando acima, ou para os campos gerados pelos operadores glob no final de cada. Se isso ocorre, depende se os globos realmente correspondem a alguma coisa. Em algumas conchas, você pode instruir um globo não resolvido a expandir para nulo - ou nada. Às vezes, isso pode ser benéfico, mas não é portátil e geralmente traz problemas adicionais - como ter que definir opções especiais do shell e depois desabilitá-las.Os únicos meios portáteis de lidar com argumentos de valor nulo envolvem variáveis vazias ou não definidas ou
~
expansões de til. E o último, a propósito, é muito mais seguro que o primeiro.Acima do shell, apenas testará qualquer um dos arquivos quanto à
-e
existência de xistence se nenhum dos três globos especificados resolver mais do que uma única correspondência. Portanto, ofor
loop é executado apenas por três ou menos iterações e apenas no caso de um diretório vazio, ou no caso em que um ou mais padrões resolvem apenas para um único arquivo. O sfor
tambémbreak
se algum dos globs representar um arquivo real - e como eu organizei os globs na ordem do mais provável para o menos provável, ele deve sair praticamente na primeira iteração todas as vezes.De qualquer forma, você deve envolver apenas uma
stat()
chamada do sistema - o shell e osls
dois devem apenas precisarstat()
do diretório consultado e listar os arquivos que seus dentries relatam que ele contém. Esta é contrastada com o comportamento defind
que, ao invés,stat()
todos os arquivos que você pode listar com ele.fonte
ls
caso. globs e[
ficam em silêncio quando não têm acesso. Por exemplo,[ -e /var/spool/cron/crontabs/stephane ]
silenciosamente reportará false, enquanto houver um arquivo com esse nome.Com o GNU ou BSDs modernos
find
, você pode:(assume
$dir
não se parece com umfind
predicado (!
,(
,-name...
).POSIXly:
fonte
[-z $dir ]
reclama que não há nenhum comando chamado[-z
na maioria dos sistemas. Você precisa de espaços ao redor dos colchetes .[ -z $dir ]
acontece que é verdadeiro sedir
estiver vazio e é falso para a maioria dos outros valores dedir
, mas não é confiável, por exemplo, é verdadeiro se o valor dedir
é= -z
ou-o -o -n -n
. Sempre use aspas duplas nas substituições de comandos (isso também vale para o resto do seu script).[ -z "$dir" ]
testa se o valor da variáveldir
está vazio. O valor da variável é uma sequência, que passa a ser o caminho para o diretório. Isso não diz nada sobre o diretório em si.Não há operador para testar se um diretório está vazio, como existe para um arquivo regular (
[ -s "$dir" ]
é verdade para um diretório mesmo que esteja vazio). Uma maneira simples de testar se um diretório está vazio é listar seu conteúdo; se você receber um texto vazio, o diretório estará vazio.Em sistemas mais antigos que não possuem
ls -A
, você pode usarls -a
, mas depois.
e..
são listados.(Não recue a linha que começa com,
..
pois a string deve conter apenas uma nova linha, não uma nova linha e espaço extra.)fonte
$(…)
é substituição de comandoVocê está olhando para os atributos do próprio diretório.
Você quer contar quantos arquivos estão lá:
Portanto, o teste para "o diretório está vazio" é:
Como isso:
fonte
Minha resposta tldr é:
É compatível com POSIX e, não importa muito, geralmente é mais rápido que a solução que lista o diretório e canaliza a saída para grep.
Uso:
Gosto da resposta /unix//a/202276/160204 , que reescrevo como:
Ele lista o diretório e canaliza o resultado para grep. Em vez disso, proponho uma função simples baseada na expansão e comparação de globos.
Esta função não é padrão POSIX e chama um subshell com
$()
. Eu explico esta função simples primeiro para que possamos entender melhor a solução final (veja a resposta tldr acima) mais tarde.Explicação:
O lado esquerdo (LHS) fica vazio quando não ocorre expansão, o que ocorre quando o diretório está vazio. A opção nullglob é necessária porque, caso contrário, quando não houver correspondência, o glob em si é o resultado da expansão. (O fato de o RHS corresponder aos globos do LHS quando o diretório está vazio não funciona devido a falsos positivos que ocorrem quando um glob LHS corresponde a um único arquivo chamado como o próprio globo:
*
o glob corresponde ao substring*
no nome do arquivo. ) A expressão entre chaves{,.[^.],..?}
abrange arquivos ocultos, mas não..
ou.
.Como
shopt -s nullglob
é executado dentro$()
(um subshell), ele não altera anullglob
opção do shell atual, o que normalmente é uma coisa boa. Por outro lado, é uma boa ideia definir essa opção nos scripts, porque é propenso a erros que um globo retorne algo quando não há correspondência. Portanto, pode-se definir a opção nullglob no início do script e isso não será necessário na função. Vamos ter isso em mente: queremos uma solução que funcione com a opção nullglob.Ressalvas:
Se não tivermos acesso de leitura ao diretório, a função reportará o mesmo como se houvesse um diretório vazio. Isso se aplica também a uma função que lista o diretório e grep a saída.
O
shopt -s nullglob
comando não é padrão POSIX.Ele usa o subshell criado por
$()
. Não é grande coisa, mas é bom se pudermos evitar.Pró:
Não que isso realmente importe, mas essa função é quatro vezes mais rápida que a anterior, medida com a quantidade de tempo de CPU gasto no kernel no processo.
Outras soluções:
Nós podemos remover o não POSIX
shopt -s nullglob
comando no LHS e colocar a corda"$1/* $1/.[^.]* $1/..?*"
no RHS e eliminar separadamente os falsos positivos que ocorrem quando temos apenas arquivos nomeados'*'
,.[^.]*
ou..?*
no diretório:Sem o
shopt -s nullglob
comando, agora faz sentido remover o subshell, mas precisamos ter cuidado, pois queremos evitar a divisão de palavras e, no entanto, permitir a expansão global no LHS. Em particular, citar para evitar a divisão de palavras não funciona, porque também impede a expansão glob. Nossa solução é considerar os globs separadamente:Ainda temos a divisão de palavras para o globo individual, mas tudo bem agora, porque isso só resultará em erro quando o diretório não estiver vazio. Adicionamos 2> / dev / null, para descartar a mensagem de erro quando houver muitos arquivos correspondentes ao glob fornecido no LHS.
Lembramos que queremos uma solução que funcione também com a opção nullglob. A solução acima falha com a opção nullglob, porque quando o diretório está vazio, o LHS também está vazio. Felizmente, nunca diz que o diretório está vazio quando não está. Ele apenas falha ao dizer que está vazio quando está. Portanto, podemos gerenciar a opção nullglob separadamente. Não podemos simplesmente adicionar os casos,
[ "$1/"* = "" ]
etc., porque eles serão expandidos como[ = "" ]
, etc., que são sintaticamente incorretos. Então, usamos[ "$1/"* "" = "" ]
etc. em vez disso. Temos novamente a considerar os três casos*
,..?*
e.[^.]*
para combinar os arquivos ocultos, mas não.
e..
. Isso não interferirá se não tivermos a opção nullglob, porque eles também nunca dizem que ela está vazia quando não está. Portanto, a solução final proposta é:Preocupação com segurança:
Crie dois arquivos
rm
ex
em um diretório vazio e execute*
no prompt. A glob*
expandirá pararm x
e isso será executado para removerx
. Isso não é uma preocupação de segurança, porque, em nossa função, os globs estão localizados onde as expansões não são vistas como comandos, mas como argumentos, assim como emfor f in *
.fonte
$(set -f; echo "$1"/*)
parece uma maneira bastante complicada de escrever"$1/*"
. E isso não corresponde a diretórios ou arquivos ocultos."$1/*"
(observe as aspas*
), portanto, oset -f
subshell e é desnecessário para isso em particular../* ./.[!.]* ./..?*
). Talvez você possa incorporar isso para completar a função.Aqui está outra maneira simples de fazer isso. Suponha que D seja o nome do caminho completo do diretório que você deseja testar para verificar o vazio.
Então
Isso funciona porque
tem como saída
O awk remove o D e se o tamanho for 0, o diretório está vazio.
fonte
fonte
echo
, tudo o que você precisa élist="$somedir/*"
. Além disso, isso é complicado e propenso a erros. Você não mencionou que o OP deve fornecer o caminho do diretório de destino, incluindo a barra final, por exemplo.