Como verificar o tamanho de um arquivo usando o Bash?

145

Eu tenho um script que verifica o tamanho 0, mas achei que deveria haver uma maneira mais fácil de verificar o tamanho dos arquivos. Ou seja, file.txté normalmente 100k; como fazer um script verificar se é menor que 90k (incluindo 0) e fazer uma nova cópia porque o arquivo está corrompido nesse caso.

O que estou usando atualmente ..

if [ -n file.txt ]
then
 echo "everything is good"
else
 mail -s "file.txt size is zero, please fix. " myemail@gmail.com < /dev/null
 # Grab wget as a fallback 
 wget -c https://www.server.org/file.txt -P /root/tmp --output-document=/root/tmp/file.txt
 mv -f /root/tmp/file.txt /var/www/file.txt
fi
user349418
fonte
1
unix.stackexchange.com/questions/16640/…
Ciro Santilli escreveu:

Respostas:

250

[ -n file.txt ]não verifica seu tamanho, verifica se a sequência file.txttem um comprimento diferente de zero e, portanto, sempre será bem-sucedida.

Se você quiser dizer "o tamanho é diferente de zero", é necessário [ -s file.txt ].

Para obter o tamanho de um arquivo, você pode usá wc -c-lo para obter o tamanho (tamanho do arquivo) em bytes:

file=file.txt
minimumsize=90000
actualsize=$(wc -c <"$file")
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize bytes
else
    echo size is under $minimumsize bytes
fi

Nesse caso, parece que é isso que você deseja.

Mas, para sua informação, se você quiser saber quanto espaço em disco o arquivo está usando, poderá du -kobter o tamanho (espaço em disco usado) em kilobytes:

file=file.txt
minimumsize=90
actualsize=$(du -k "$file" | cut -f 1)
if [ $actualsize -ge $minimumsize ]; then
    echo size is over $minimumsize kilobytes
else
    echo size is under $minimumsize kilobytes
fi

Se você precisar de mais controle sobre o formato de saída, também poderá ver stat. No Linux, você começaria com algo como stat -c '%s' file.txt, e no BSD / Mac OS X, algo como stat -f '%z' file.txt.

Mikel
fonte
5
Por que ao du -b "$file" | cut -f 1invés de stat -c '%s' "$file"? Ou stat --printf="%s" "$file"?
mivk
1
Só porque é mais portátil. BSD e Linux stat têm sinalizadores diferentes.
Mikel
1
Eu tive que modificá-lo ... | cut -d' ' -f1para fazê-lo funcionar no Ubuntu.
Mikepote
8
Use wc -c < "$file"(observe o <), caso em que você não precisa da | cut ...peça (que, conforme publicada, não funciona no OSX). O BLOCKSIZEvalor mínimo para duno OSX é 512.
mklement0
3
@PetriSirkkala No meu sistema Linux, wc -c <filenametambém usa fstate seek? Observe que fstatleva um fd, não um nome de caminho.
26417 Mikel
24

Surpreende-me que ninguém tenha mencionado stato tamanho do arquivo. Alguns métodos são definitivamente melhores: usar -spara descobrir se o arquivo está vazio ou não é mais fácil do que qualquer outra coisa, se é tudo o que você deseja. E se você deseja encontrar arquivos de um tamanho, findcertamente é o caminho a percorrer.

Também gosto dumuito de obter o tamanho do arquivo em kb, mas, para bytes, eu usaria stat:

size=$(stat -f%z $filename) # BSD stat

size=$(stat -c%s $filename) # GNU stat?
Daniel C. Sobral
fonte
2
staté uma ótima idéia, mas no CentOS foi isso que funcionou para mim: #size=$(stat -c%s $filename)
Oz Solomon
2
A diferença entre GNU e BSD é o que, infelizmente, torna essa alternativa um pouco menos atraente. :(
lapo 29/10
1
stat pode ser enganoso se o arquivo for escasso. Você pode usar os blocos relatados pelo stat para calcular o espaço usado.
Ajith Antony
@AjithAntony Esse é um ponto interessante que não me ocorreu. Eu posso ver stata coisa certa em algumas situações, e arquivos esparsos não são relevantes na maioria das situações, embora certamente não todos.
Daniel C. Sobral
17

solução alternativa com awk e parêntese duplo:

FILENAME=file.txt
SIZE=$(du -sb $FILENAME | awk '{ print $1 }')

if ((SIZE<90000)) ; then 
    echo "less"; 
else 
    echo "not less"; 
fi
fstab
fonte
1
Bom, mas não funciona no OSX, onde dunão suporta -b. (Pode ser uma escolha de estilo consciente, mas apenas para mencionar a alternativa: você pode omitir o $interior prefixo (( ... ))ao fazer referência a variáveis: ((SIZE<90000)))
mklement0
1
Na verdade, foi uma edição de um usuário anterior que pensou que era errado para omitir a$
fstab
2
@fstab, você pode omitir awkusando read( bashcomando interno):read SIZE _ <<<$(du -sb "$FILENAME")
Jdamian
13

Se você findlida com essa sintaxe, você pode usá-la:

find -maxdepth 1 -name "file.txt" -size -90k

Isso resultará file.txtem stdout se e somente se o tamanho de file.txtfor menor que 90k. Para executar um script scriptse file.txttiver um tamanho menor que 90k:

find -maxdepth 1 -name "file.txt" -size -90k -exec script \;
gniourf_gniourf
fonte
3
+1, mas também para fazê-lo funcionar no OSX, você precisa de um argumento diretório de destino explícito, por exemplo:find . -maxdepth 1 -name "file.txt" -size -90k
mklement0
8

Se você está procurando apenas o tamanho de um arquivo:

$ cat $file | wc -c
> 203233
BananaNeil
fonte
1
Essa pode ser a resposta mais curta e viável, mas provavelmente também é a mais lenta. :)
SunSparc 25/08
2
Sim, mas certamente economicamente superior: Custo do tempo de engenharia> Custo do tempo de computação
BananaNeil
8
wc -c "$file"foi dada como resposta em 2011 (três anos atrás). Sim, wc -c "$file"tem o problema de exibir o nome do arquivo e a contagem de caracteres; portanto, as respostas anteriores adicionaram um comando para separar a contagem. Mas wc -c < "$file", que corrige esse problema, foi adicionado como comentário em maio de 2014. Sua resposta é equivalente a isso, exceto que ela adiciona um "uso inútil de cat" . Além disso, você deve citar todas as referências de variáveis ​​do shell, a menos que tenha um bom motivo para não fazê-lo.
G-Man diz 'Reinstate Monica'
1
Você pode tornar isso mais eficiente usando head -c em vez de cat.if [$ (head -c 90000 $ arquivo | wc -c) -lt 90000]; em seguida, ecoa "O arquivo é menor que 90k"; fi. Testado no CentOS, ele pode ou não funcionar no BSD ou OSX.
22617 Kevin Keane
@BananaNeil como fazer esse processo a cada 20 segundos para que eu possa verificar o aumento do tamanho do arquivo etc.
A Sahra 27/03
6

Isso funciona tanto em linux quanto em macos

function filesize
{
    local file=$1
    size=`stat -c%s $file 2>/dev/null` # linux
    if [ $? -eq 0 ]
    then
        echo $size
        return 0
    fi

    eval $(stat -s $file) # macos
    if [ $? -eq 0 ]
    then
        echo $st_size
        return 0
    fi

    return -1
}
Neil McGill
fonte
5

O stat parece fazer isso com o menor número de chamadas do sistema:

$ set debian-live-8.2.0-amd64-xfce-desktop.iso

$ strace stat --format %s $1 | wc
    282    2795   27364

$ strace wc --bytes $1 | wc
    307    3063   29091

$ strace du --bytes $1 | wc
    437    4376   41955

$ strace find $1 -printf %s | wc
    604    6061   64793

fonte
Se eu entendi corretamente, o teste deve ser feito com também o redirecionamento de tubulação ?: strace du --bytes $1 2>&1 >/dev/null | wc Se for esse o caso, então em amd64 arquitetura no ArchLinux (versões mais recentes geralmente de tudo) Eu tenho 45 linhas para du, 46 linhas para stat, 47 linhas para wce 72 linhas para find.
VasiliNovikov
5
python -c 'import os; print (os.path.getsize("... filename ..."))'

portátil, todos os tipos de python, evita variação nos dialetos estatísticos

user6336835
fonte
4

Para obter o tamanho do arquivo no Linux e no Mac OS X (e provavelmente em outros BSDs), não há muitas opções, e a maioria das sugeridas aqui funcionará apenas em um sistema.

Dado f=/path/to/your/file,

o que funciona no Linux e no Mac 's Bash:

size=$( perl -e 'print -s shift' "$f" )

ou

size=$( wc -c "$f" | awk '{print $1}' )

As outras respostas funcionam bem no Linux, mas não no Mac:

  • dunão tem uma -bopção no Mac e o truque BLOCKSIZE = 1 não funciona ("o tamanho mínimo do bloco é 512", o que leva a um resultado errado)

  • cut -d' ' -f1 não funciona porque no Mac, o número pode estar alinhado à direita, preenchido com espaços à frente.

Então, se você precisa de algo flexível, ou é perl's -soperador ou wc -ccanalizada para awk '{print $1}'(awk irá ignorar o espaço em branco à esquerda).

E, é claro, com relação ao restante da sua pergunta original, use o operador -lt(ou -gt):

if [ $size -lt $your_wanted_size ]; then etc.

mivk
fonte
3
+1; se você souber que só usará o tamanho em um contexto aritmético (onde o espaço em branco à esquerda é ignorado), você pode simplificar size=$(wc -c < "$f")(observe o <que faz wccom que apenas relate um número). Re comparação: não se esqueça do mais "bash-ful" if (( size < your_wanted_size )); then ...(e também [[ $size -lt $your_wanted_size ]]).
mklement0
3

Com base na resposta de gniourf_gniourf,

find "file.txt" -size -90k

vai escrever file.txtpara stdout se e somente se o tamanho file.txté menor que 90K, e

encontre "file.txt" -size -90k -exec command \;

executará o comando commandse file.txttiver um tamanho menor que 90K. Eu testei isso no Linux. De find(1),

... argumentos de linha de comando seguinte (os -H, -Le -Popções) são tidas como nomes de arquivos ou diretórios a serem examinados, até o primeiro argumento que começa com '-', ...

(enfase adicionada).

G-Man Diz 'Reinstate Monica'
fonte
1
ls -l $file | awk '{print $6}'

assumindo que o comando ls reporte o tamanho do arquivo na coluna 6

yeugeniuss
fonte
1

Gostaria de usar du's --thresholdpara isso. Não tenho certeza se esta opção está disponível em todas as versões, dumas está implementada na versão do GNU.

Citando o manual do du (1) :

-t, --threshold=SIZE
       exclude entries smaller than SIZE if positive, or entries greater
       than SIZE if negative

Aqui está a minha solução, usando du --threshold=para o caso de uso do OP:

THRESHOLD=90k
if [[ -z "$(du --threshold=${THRESHOLD} file.txt)" ]]; then
    mail -s "file.txt size is below ${THRESHOLD}, please fix. " myemail@gmail.com < /dev/null
    mv -f /root/tmp/file.txt /var/www/file.txt
fi

A vantagem de que, é que dupode aceitar um argumento para essa opção em um formato conhecido - tanto humana como em 10K, 10MiBou o que nunca você se sinta confortável - você não precisa converter manualmente entre formatos / unidades desde dualças que.

Para referência, aqui está a explicação sobre esse SIZEargumento na página de manual:

The SIZE argument is an integer and optional unit (example: 10K is 
10*1024). Units are K,M,G,T,P,E,Z,Y (powers of 1024) or KB,MB,... (powers
of 1000). Binary prefixes can be used, too: KiB=K, MiB=M, and so on.
Doron Behar
fonte
+1 Excelente opção. Infelizmente, alguns de nós estão presos a versões mais antigas duque não são compatíveis. A --thresholdopção foi adicionada no coreutils 8.21, lançado em 2013 .
Amit Naidu
1

Ok, se você estiver em um Mac, faça o seguinte: stat -f %z "/Users/Example/config.log" É isso!

GarfExiXD
fonte