Como posso obter o tamanho de um arquivo em um script bash?


246

Como posso obter o tamanho de um arquivo em um script bash?

Como atribuo isso a uma variável bash para que eu possa usá-lo mais tarde?



1
Par isso com pve catpara um comando de cópia que mostra o progresso e ETA :)
sudo

stat -c% s file.name
neverMind9

Respostas:


242

Sua melhor aposta se em um sistema GNU:

stat --printf="%s" file.any

Do man stat :

% s tamanho total, em bytes

Em um script bash:

#!/bin/bash
FILENAME=/home/heiko/dummy/packages.txt
FILESIZE=$(stat -c%s "$FILENAME")
echo "Size of $FILENAME = $FILESIZE bytes."

NOTA: consulte a resposta da @ chbrown para saber como usar o stat no terminal no Mac OS X.


7
@ haunted85 staté a maneira mais direta, supondo que você esteja usando Linux ou Cygwin ( statnão é padrão). wc -ccomo sugerido por Eugéne é portátil.
Gilles

2
stat: illegal option -- c
Iulian Onofrei 27/04

stat --printf="%s" file.txtnão exibe nenhum output no Debian Jessie ...
woohoo

5
No MacOS, isso funciona:stat -f%z myfile.tar
ccpizza

2
@woohoo Seu prompt sobrescreve a saída. man statdiz que --printf omite a nova linha à direita. Use --formatou -cpara ver a saída. Obtenha mais informações comparando stat --printf="%s" file.any | xxd -comstat -c "%s" file.any | xxd -
neto

92
file_size_kb=`du -k "$filename" | cut -f1`

O problema com o uso staté que é uma extensão GNU (Linux). du -ke cut -f1são especificados pelo POSIX e, portanto, são portáteis para qualquer sistema Unix.

O Solaris, por exemplo, é enviado com bash, mas não com stat. Portanto, isso não é totalmente hipotético.

lstem um problema semelhante, pois o formato exato da saída não está especificado, portanto, a análise da saída não pode ser feita de maneira portável. du -htambém é uma extensão GNU.

Atenha-se a construções portáteis sempre que possível, e você facilitará a vida de alguém no futuro. Talvez você mesmo.


48
dunão fornece o tamanho do arquivo, fornece uma indicação de quanto espaço o arquivo usa, que é sutilmente diferente (geralmente o tamanho relatado por dué o tamanho do arquivo arredondado para o número mais próximo de blocos, em que um bloco é tipicamente 512B ou 1kB ou 4kB).
Gilles

7
@Gilles, arquivos esparsos (ou seja, arquivos com orifícios) relatam menos que o comprimento.
vonbrand

5
Esta, com --bytesou em -bvez de -k, deve ser a resposta aceita.
Amedee Van Gasse

1
A opção -h("humana") dedu produzirá a resposta mais apropriada para casos gerais:, file_size=`du -h "$filename" | cut -f1pois exibirá K (kilobytes), M (Megabytes) ou G (Gigabytes) conforme apropriado.
fralau 1/04

1
@fralau: O OP quer "atribuir isso a uma variável do bash para que eles possam usá-lo mais tarde"; portanto, é muito mais provável que eles desejem um valor numérico real, não uma aproximação legível por humanos. Além disso, -hé uma extensão GNU; não é padrão
Nemo

74

Você também pode usar o comando "word count" ( wc):

wc -c "$filename" | awk '{print $1}'

O problema wcé que ele adicionará o nome do arquivo e recuará a saída. Por exemplo:

$ wc -c somefile.txt
    1160 somefile.txt

Se você deseja evitar encadear um editor de idioma ou fluxo interpretado completo apenas para obter uma contagem de tamanho de arquivo, basta redirecionar a entrada do arquivo para que wcnunca veja o nome do arquivo:

wc -c < "$filename"

Esse último formulário pode ser usado com substituição de comando para capturar facilmente o valor que você estava procurando como variável de shell, conforme mencionado por Gilles abaixo.

size="$(wc -c <"$filename")"

30
wc -c <"$FILENAME"dá o tamanho sem outra crosta, portanto size=$(wc -c <"$FILENAME").
Gilles

6
Apenas mais um ponto: acabei de testá-lo e wc -c < fileparece ser muito rápido, pelo menos no OS X. Suponho que o wc tenha o cérebro para tentar definir o arquivo se apenas -c for especificado.
Edward Falk

4
@EdwardFalk: o GNU wc -cusa fstat, mas depois procura o penúltimo bloco do arquivo e lê os últimos st_blksizebytes atualizados . Aparentemente, isso ocorre porque os arquivos no Linux /proce, /syspor exemplo, têm tamanhos estatísticos que são apenas aproximados e wcdesejam reportar o tamanho real, não o tamanho relatado pelo stat. Eu acho que seria estranho wc -creportar um tamanho diferente wc, mas não é idéia ler dados do arquivo se for um arquivo de disco normal e não estiver na memória. Ou armazenamento em fita pior, near-line ...
Peter Cordes

1
Parece que printfainda vê o recuo, por exemplo printf "Size: $size"- -> size: <4 spaces> 54339. Por outro lado, echoignora o espaço em branco. Alguma maneira de torná-lo consistente?
Eugene Kulabuhov

2
@keithpjolley: ligando fstat. Tente correr strace wc -c </etc/passwde você pode ver o que está fazendo.
Nemo

48

O BSD (Mac OS X) stattem um sinalizador de argumento de formato diferente e especificadores de campo diferentes. De man stat(1):

  • -f format: Exibe informações usando o formato especificado. Consulte a seção FORMATS para obter uma descrição dos formatos válidos.
  • ... a seção FORMATS ...
  • z: O tamanho do arquivo em bytes.

Então, todos juntos agora:

stat -f%z myfile1.txt

28

Depende do que você quer dizer com tamanho .

size=$(wc -c < "$file")

fornecerá o número de bytes que podem ser lidos no arquivo. IOW, é o tamanho do conteúdo do arquivo. Terá, no entanto ler o conteúdo do arquivo (exceto se o arquivo é um arquivo regular ou link simbólico para arquivo regular na maioria das wcimplementações como uma otimização). Isso pode ter efeitos colaterais. Por exemplo, para um pipe nomeado, o que foi lido não pode mais ser lido novamente e para coisas como /dev/zeroou /dev/randomque são de tamanho infinito, vai demorar um pouco. Isso também significa que você precisa de readpermissão para o arquivo e o último registro de data e hora de acesso ao arquivo pode ser atualizado.

Isso é padrão e portátil, no entanto, observe que algumas wcimplementações podem incluir espaços em branco iniciais nessa saída. Uma maneira de se livrar deles é usar:

size=$(($(wc -c < "$file")))

ou para evitar um erro sobre uma expressão aritmética vazia em dashou yashquando wcnão produz saída (como quando o arquivo não pode ser aberto):

size=$(($(wc -c < "$file") +0))

ksh93foi wcincorporado (desde que você o habilite, também é possível invocá-lo como command /opt/ast/bin/wc), o que o torna mais eficiente para arquivos regulares nesse shell.

Vários sistemas possuem um comando chamado statinterface para as chamadas stat()ou lstat()sistema.

Essas informações de relatório encontradas no inode. Uma dessas informações é o st_sizeatributo Para arquivos regulares, esse é o tamanho do conteúdo (quantos dados podem ser lidos na ausência de erro (é o que a maioria das wc -cimplementações usa na otimização)). Para links simbólicos, esse é o tamanho em bytes do caminho de destino. Para pipes nomeados, dependendo do sistema, é 0 ou o número de bytes atualmente no buffer do pipe. O mesmo para dispositivos de bloco, onde, dependendo do sistema, você obtém 0 ou o tamanho em bytes do armazenamento subjacente.

Você não precisa de permissão de leitura para o arquivo para obter essas informações, apenas pesquise permissão no diretório ao qual está vinculado.

Por ordem cronológica, existe:

  • IRIXstat (anos 90):

    stat -qLs -- "$file"

    retorna o st_sizeatributo de $file( lstat()) ou:

    stat -s -- "$file"

    mesmo, exceto quando $filehouver um link simbólico; nesse caso, será st_sizeo arquivo após a resolução do link simbólico.

  • zsh statbuiltin (agora também conhecido como zstat) no zsh/statmódulo (carregado com zmodload zsh/stat) (1997):

    stat -L +size -- $file # st_size of file
    stat +size -- $file    # after symlink resolution

    ou para armazenar em uma variável:

    stat -L -A size +size -- $file

    obviamente, esse é o mais eficiente nesse shell.

  • GNUstat (2001); também no BusyBox statdesde 2005 (copiado do GNU stat):

    stat -c %s -- "$file"  # st_size of file
    stat -Lc %s -- "$file" # after symlink resolution

    (observe que o significado de -Lé revertido em comparação com IRIX ou zsh stat.

  • BSDsstat (2002):

    stat -f %z -- "$file"  # st_size of file
    stat -Lf %z -- "$file" # after symlink resolution

Ou você pode usar a função stat()/ lstat()de alguma linguagem de script como perl:

perl -le 'print((lstat shift)[7])' -- "$file"

O AIX também possui um istatcomando que irá despejar todas as informações stat()(não lstat(), portanto, não funcionará em links simbólicos) e com as quais você pode pós-processar, por exemplo:

LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'

(obrigado @JeffSchaller pela ajuda para descobrir os detalhes ).

Em tcsh:

@ size = -Z $file:q

(tamanho após a resolução do link simbólico)

Muito antes do GNU introduzir seu statcomando, o mesmo poderia ser alcançado com o findcomando GNU com seu -printfpredicado (já em 1991):

find -- "$file" -prune -printf '%s\n'    # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution

Um problema, porém, é que não funciona se $filecomeça com -ou é um findpredicado (como !, (...).

O comando padrão para obter as informações stat()/ lstat()é ls.

POSIXly, você pode fazer:

LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'

e adicione -Lo mesmo após a resolução do link simbólico. Isso não funciona para arquivos de dispositivo, embora o campo seja o número principal do dispositivo, em vez do tamanho.

Para dispositivos de bloco, os sistemas em que stat()retorna 0 st_sizegeralmente têm outras APIs para relatar o tamanho do dispositivo de bloco. Por exemplo, o Linux possui BLKGETSIZE64 ioctl(), e a maioria das distribuições Linux agora é fornecida com um blockdevcomando que pode fazer uso dele:

blockdev --getsize64 -- "$device_file"

No entanto, você precisa de permissão de leitura para o arquivo do dispositivo. Geralmente é possível derivar o tamanho por outros meios. Por exemplo (ainda no Linux):

lsblk -bdno size -- "$device_file"

Deve funcionar, exceto para dispositivos vazios.

Uma abordagem que funciona para todos os arquivos buscáveis (incluindo arquivos comuns, a maioria dos dispositivos de bloco e alguns dispositivos de caracteres) é abrir o arquivo e procurar até o fim:

  • Com zsh(após carregar o zsh/systemmódulo):

    {sysseek -w end 0 && size=$((systell(0)))} < $file
  • Com ksh93:

    < "$file" <#((size=EOF))

    ou

    { size=$(<#((EOF))); } < "$file"
  • com perl:

    perl -le 'seek STDIN, 0, 2 or die "seek: $!"; print tell STDIN' < "$file"

Para pipes nomeados, temos visto que alguns sistemas (AIX, Solaris, HP / UX, pelo menos) fazer a quantidade de dados em um buffer de cano disponível em stat()'s st_size. Alguns (como Linux ou FreeBSD) não.

No Linux, pelo menos, você pode usar o FIONREAD ioctl()depois de abrir o canal (no modo de leitura + gravação para evitar travamento):

fuser -s -- "$fifo_file" && 
  perl -le 'require "sys/ioctl.ph";
            ioctl(STDIN, &FIONREAD, $n) or die$!;
            print unpack "L", $n' <> "$fifo_file"

No entanto, observe que, embora ele não leia o conteúdo do pipe, a simples abertura do pipe nomeado aqui ainda pode ter efeitos colaterais. Estamos usando fuserpara verificar primeiro se algum processo já possui o canal aberto para aliviá-lo, mas isso não é infalível, pois fuserpode não ser capaz de verificar todos os processos.

Agora, até agora, consideramos apenas o tamanho dos dados primários associados aos arquivos. Isso não leva em conta o tamanho dos metadados e toda a infraestrutura de suporte necessária para armazenar esse arquivo.

Outro atributo inode retornado por stat()é st_blocks. Esse é o número de blocos de 512 bytes usados ​​para armazenar os dados do arquivo (e algumas vezes alguns de seus metadados, como os atributos estendidos nos sistemas de arquivos ext4 no Linux). Isso não inclui o próprio inode ou as entradas nos diretórios aos quais o arquivo está vinculado.

O tamanho e o uso do disco não estão necessariamente intimamente relacionados como compactação, escassez (às vezes alguns metadados), infraestrutura extra como blocos indiretos em alguns sistemas de arquivos que influenciam este último.

Isso é normalmente o que duusa para relatar o uso do disco. A maioria dos comandos listados acima poderá obter essas informações.

  • POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
  • POSIXLY_CORRECT=1 du -s -- "$file" (não para diretórios nos quais isso incluiria o uso do disco dos arquivos).
  • GNU find -- "$file" -printf '%b\n'
  • zstat -L +block -- $file
  • GNU stat -c %b -- "$file"
  • BSD stat -f %b -- "$file"
  • perl -le 'print((lstat shift)[12])' -- "$file"

claramente a resposta mais abrangente e informativa. obrigado. i pode usar isso para criar scripts plataforma festança cruzadas usando o BSD e GNU Status de informações
oligofren

1
Curiosidade: o GNU coreutils wc -cusa fstat, mas depois lê os últimos st_blksizebytes atualizados . Aparentemente, isso ocorre porque os arquivos no Linux /proce, /syspor exemplo, têm tamanhos de estatística que são apenas aproximados . Isso é bom para correção, mas ruim se o final do arquivo estiver no disco e não na memória (especialmente se usado em muitos arquivos em um loop). E muito ruim se o arquivo for migrado para o armazenamento em fita quase na linha ou por exemplo, um sistema de arquivos de descompressão transparente do FUSE.
Peter Cordes

não funcionaria tambémls -go file | awk '{print $3}'
Steven Penny

@StevenPenny esses -goseriam os SysV, eles não funcionariam em BSDs (opcional (XSI) no POSIX). Você também precisaria ls -god file | awk '{print $3; exit}'( -dpara trabalhar em diretórios, exitpara links simbólicos com novas linhas no destino). Os problemas com os arquivos do dispositivo também permanecem.
Stéphane Chazelas

1
@ a API do Unix não faz distinção entre texto e arquivos binários. São todas as sequências de bytes. Alguns aplicativos podem querer interpretar esses bytes como texto, mas obviamente não wc -cinformam o número de bytes.
Stéphane Chazelas

22

Este script combina várias maneiras de calcular o tamanho do arquivo:

(
  du --apparent-size --block-size=1 "$file" 2>/dev/null ||
  gdu --apparent-size --block-size=1 "$file" 2>/dev/null ||
  find "$file" -printf "%s" 2>/dev/null ||
  gfind "$file" -printf "%s" 2>/dev/null ||
  stat --printf="%s" "$file" 2>/dev/null ||
  stat -f%z "$file" 2>/dev/null ||
  wc -c <"$file" 2>/dev/null
) | awk '{print $1}'

O script funciona em muitos sistemas Unix, incluindo Linux, BSD, OSX, Solaris, SunOS, etc.

O tamanho do arquivo mostra o número de bytes. É o tamanho aparente, que são os bytes que o arquivo usa em um disco típico, sem compactação especial ou áreas esparsas especiais ou blocos não alocados etc.

Este script possui uma versão de produção com mais ajuda e mais opções aqui: https://github.com/SixArm/file-size


9

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

8

ls -l filename fornecerá muitas informações sobre um arquivo, incluindo seu tamanho, permissões e proprietário.

O tamanho do arquivo na quinta coluna e é exibido em bytes. No exemplo abaixo, o tamanho do arquivo está abaixo de 2 KB:

-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php

Edit: Isso aparentemente não é tão confiável quanto o statcomando.


Eu acho que ambos ls -le statcomando fornecem informações de tamanho confiáveis. Não encontrei nenhuma referência ao contrário. ls -sdará tamanho em número de blocos.
dabest1

2
@ dabest1 não é confiável no sentido de que em outro unix, a saída deles pode ser diferente (e em alguns unixes é).
Eugene Bujak

Sim, IIRC, o Solaris não exibiu o nome do grupo por padrão, levando a menos colunas na saída.
Edward Falk

Como o tamanho é numérico puro, cercado por espaços em branco, e a data do ano é numérico puro, em um formato definido, seria possível usar um regexp para tratar usuário + proprietário como um campo, independentemente de o grupo estar ou não presente. (um exercício para o leitor!)
MikeW 21/02

5

du filename informará o uso do disco em bytes.

Eu prefiro du -h filename, que fornece o tamanho em um formato legível por humanos.


2
ou que stat -c "%s";)

1
Esse tipo de duimpressão imprime o tamanho em blocos de 1024 bytes, e não uma simples contagem de bytes.
Peter Lyons

Observe que o padrão dufornece uma saída em número de unidades de 512 bytes. O GNU duusa kibibytes, a menos que seja chamado com POSIXLY_CORRECTem seu ambiente.
Stéphane Chazelas

1
Para arquivos do tipo diretório , isso fornece ao disco o uso do diretório, mas também de todos os outros arquivos dentro (recursivamente).
Stéphane Chazelas

3

Crie pequenas funções utilitárias em seus scripts de shell que você pode delegar.

Exemplo

#! /bin/sh -
# vim: set ft=sh

# size utility that works on GNU and BSD systems
size(){
    case $(uname) in
        (Darwin | *BSD*)
            stat -Lf %z -- "$1";;
        (*) stat -c %s -- "$1"
    esac
}

for f do
    printf '%s\n' "$f : $(gzip < "$f" | wc -c) bytes (versus $(size "$f") bytes)"
done

Com base nas informações da resposta de @ Stéphane Chazelas.


Veja também gzip -v < file > /dev/nullpara verificar a compressibilidade de um arquivo.
Stéphane Chazelas

@ StéphaneChazelas não tenho certeza se acho que foi uma melhoria. essas declarações de caso podem facilmente adiar noobs; Eu certamente nunca me lembro de como fazê-las :-) as declarações de caso são inerentemente mais portáteis desde que você fez isso? Eu vejo o ponto em que há mais de dois casos, mas caso contrário ... +
oligofren

1
Suponho que seja também uma questão de gosto, mas aqui é o caso típico em que você deseja usar uma casedeclaração. caseé a construção Bourne / POSIX para fazer a correspondência de padrões. [[...]]é apenas ksh / bash / zsh (com variações).
Stéphane Chazelas

2

Encontrei um liner AWK 1 e ele tinha um bug, mas eu o corrigi. Eu também adicionei no PetaBytes depois do TeraBytes.

FILE_SIZE=234234 # FILESIZE IN BYTES
FILE_SIZE=$(echo "${FILE_SIZE}" | awk '{ split( "B KB MB GB TB PB" , v ); s=1; while( $1>1024 ){ $1/=1024; s++ } printf "%.2f %s", $1, v[s] }')

Considerando que o stat não está em todos os sistemas, você quase sempre pode usar a solução AWK. Exemplo; o Raspberry Pi não possui estatísticas, mas possui awk .


1
Completamente, NÃO o que o OP pediu, mas um pequeno pedaço de trabalho.
Gypsy Spellweaver

0

Uma outra maneira compatível com POSIX seria usar awkcom sua length()função que retorna o comprimento, em caracteres em cada linha do arquivo de entrada, excluindo os caracteres de nova linha. Então, fazendo

awk '{ sum+=length } END { print sum+NR }' file

garantimos que ele NRseja adicionado sum, resultando na contagem total de caracteres e no número total de novas linhas encontradas no arquivo. A length()função awkaceita um argumento que, por padrão, significa length($0)que é a linha inteira atual.


Não se a última linha não terminar em uma nova linha: printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'deve imprimir 3, mas imprime 4.
Isaac

-1

Eu também gosto da opção wc. Emparelhado com 'bc', você pode obter casas decimais em quantas casas desejar.

Eu estava olhando para melhorar um script que tinha despertado a coluna 'tamanho do arquivo' de um comando 'ls -alh'. Eu não queria apenas tamanhos de arquivos inteiros e duas casas decimais pareciam se adequar; portanto, depois de ler essa discussão, criei o código abaixo.

Sugiro quebrar a linha nos pontos e vírgulas se você incluir isso em um script.

file=$1; string=$(wc -c $file); bite=${string% *}; okay=$(echo "scale=2; $bite/1024" | bc);friend=$(echo -e "$file $okay" "kb"); echo -e "$friend"

Meu script é chamado gpfl , para "obter tamanho do arquivo de imagem". Eu o uso depois de fazer uma mogrificação em um arquivo no imagemagick, antes de abrir ou recarregar uma imagem em um visualizador jpeg da GUI.

Não sei como isso se classifica como uma "resposta", pois empresta muito do que já foi oferecido e discutido. Então eu vou deixar lá.

BZT


1
Eu preferiria usar "stat" ou "ls". Normalmente, eu não gosto de usar "wc" para obter tamanhos de arquivo, porque ele lê fisicamente o arquivo inteiro. Se você possui muitos arquivos, ou arquivos particularmente grandes, isso pode levar muito tempo. Mas sua solução é criativa ... + 1.
precisa

2
Eu concordo com a noção de usar "stat" sobre "wc" para o tamanho do arquivo; no entanto, se você usar "wc -c", nenhum dado será lido; em vez disso, lseek será usado para descobrir o número de bytes em um arquivo. Você está em
Home

1
@ bbaja42: note que o GNU Coreutils wclê o último bloco do arquivo, caso tenha stat.st_sizesido apenas uma aproximação (como para Linux /proce /sysarquivos). Acho que eles não decidiu fazer o comentário principal mais complicada quando eles acrescentaram que a lógica de um par de linhas para baixo: lingrok.org/xref/coreutils/src/wc.c#246
Peter Cordes

-1

O método mais rápido e mais simples (IMO) é:

bash_var=$(stat -c %s /path/to/filename)

2
Em seguida, vote uma ou mais das respostas existentes que mencionam stat; não há necessidade de repeti-lo novamente ...
Jeff Schaller

1
@JeffSchaller Acabei de votar na resposta de Stephane seguindo as suas instruções. Eu acho que é muito complicado para os meus propósitos. Foi por isso que publiquei esta resposta simples para almas afins.
WinEunuuchs2Unix

1
Obrigado; é que uma sexta instância de uma resposta "stat" não simplifica essas perguntas e respostas, mas prefere que um novo leitor se pergunte "como essa resposta é diferente das outras?" e levar a mais confusão em vez de menos.
Jeff Schaller

@JeffSchaller, eu acho. Mas eu poderia reclamar das muitas due wcrespostas que deveriam ter um aviso de responsabilidade NUNCA FAZER ISSO na vida real. Acabei de usar minha resposta em um aplicativo da vida real hoje à noite e achei que valia a pena compartilhar. Eu acho que todos nós temos nossos ombros de opinião .
WinEunuuchs2Unix
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.