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?
pv
e cat
para um comando de cópia que mostra o progresso e ETA :)
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?
pv
e cat
para um comando de cópia que mostra o progresso e ETA :)
Respostas:
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.
stat
é a maneira mais direta, supondo que você esteja usando Linux ou Cygwin ( stat
não é padrão). wc -c
como sugerido por Eugéne é portátil.
stat: illegal option -- c
stat --printf="%s" file.txt
não exibe nenhum output no Debian Jessie ...
stat -f%z myfile.tar
man stat
diz que --printf omite a nova linha à direita. Use --format
ou -c
para ver a saída. Obtenha mais informações comparando stat --printf="%s" file.any | xxd -
comstat -c "%s" file.any | xxd -
file_size_kb=`du -k "$filename" | cut -f1`
O problema com o uso stat
é que é uma extensão GNU (Linux). du -k
e cut -f1
sã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.
ls
tem 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 -h
també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.
du
nã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).
--bytes
ou em -b
vez de -k
, deve ser a resposta aceita.
-h
("humana") dedu
produzirá a resposta mais apropriada para casos gerais:, file_size=`du -h "$filename" | cut -f1
pois exibirá K (kilobytes), M (Megabytes) ou G (Gigabytes) conforme apropriado.
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 wc
nunca 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")"
wc -c <"$FILENAME"
dá o tamanho sem outra crosta, portanto size=$(wc -c <"$FILENAME")
.
wc -c < file
parece 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.
wc -c
usa fstat
, mas depois procura o penúltimo bloco do arquivo e lê os últimos st_blksize
bytes atualizados . Aparentemente, isso ocorre porque os arquivos no Linux /proc
e, /sys
por exemplo, têm tamanhos estatísticos que são apenas aproximados e wc
desejam reportar o tamanho real, não o tamanho relatado pelo stat. Eu acho que seria estranho wc -c
reportar 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 ...
printf
ainda vê o recuo, por exemplo printf "Size: $size"
- -> size: <4 spaces> 54339
. Por outro lado, echo
ignora o espaço em branco. Alguma maneira de torná-lo consistente?
fstat
. Tente correr strace wc -c </etc/passwd
e você pode ver o que está fazendo.
O BSD (Mac OS X) stat
tem 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.z
: O tamanho do arquivo em bytes.Então, todos juntos agora:
stat -f%z myfile1.txt
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 wc
implementaçõ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/zero
ou /dev/random
que são de tamanho infinito, vai demorar um pouco. Isso também significa que você precisa de read
permissã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 wc
implementaçõ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 dash
ou yash
quando wc
não produz saída (como quando o arquivo não pode ser aberto):
size=$(($(wc -c < "$file") +0))
ksh93
foi wc
incorporado (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 stat
interface para as chamadas stat()
ou lstat()
sistema.
Essas informações de relatório encontradas no inode. Uma dessas informações é o st_size
atributo 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 -c
implementaçõ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_size
atributo de $file
( lstat()
) ou:
stat -s -- "$file"
mesmo, exceto quando $file
houver um link simbólico; nesse caso, será st_size
o arquivo após a resolução do link simbólico.
zsh
stat
builtin (agora também conhecido como zstat
) no zsh/stat
mó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 stat
desde 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 istat
comando 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 stat
comando, o mesmo poderia ser alcançado com o find
comando GNU com seu -printf
predicado (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 $file
começa com -
ou é um find
predicado (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 -L
o mesmo após a resolução do link simbólico. Isso não funciona para arquivos de dispositivo, embora o 5º campo seja o número principal do dispositivo, em vez do tamanho.
Para dispositivos de bloco, os sistemas em que stat()
retorna 0 st_size
geralmente 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 blockdev
comando 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/system
mó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 fuser
para verificar primeiro se algum processo já possui o canal aberto para aliviá-lo, mas isso não é infalível, pois fuser
pode 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 du
usa 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).find -- "$file" -printf '%b\n'
zstat -L +block -- $file
stat -c %b -- "$file"
stat -f %b -- "$file"
perl -le 'print((lstat shift)[12])' -- "$file"
wc -c
usa fstat
, mas depois lê os últimos st_blksize
bytes atualizados . Aparentemente, isso ocorre porque os arquivos no Linux /proc
e, /sys
por 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.
ls -go file | awk '{print $3}'
-go
seriam os SysV, eles não funcionariam em BSDs (opcional (XSI) no POSIX). Você também precisaria ls -god file | awk '{print $3; exit}'
( -d
para trabalhar em diretórios, exit
para links simbólicos com novas linhas no destino). Os problemas com os arquivos do dispositivo também permanecem.
wc -c
informam o número de bytes.
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
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
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 stat
comando.
ls -l
e stat
comando fornecem informações de tamanho confiáveis. Não encontrei nenhuma referência ao contrário. ls -s
dará tamanho em número de blocos.
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.
du
impressão imprime o tamanho em blocos de 1024 bytes, e não uma simples contagem de bytes.
du
fornece uma saída em número de unidades de 512 bytes. O GNU du
usa kibibytes, a menos que seja chamado com POSIXLY_CORRECT
em seu ambiente.
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.
gzip -v < file > /dev/null
para verificar a compressibilidade de um arquivo.
case
declaração. case
é a construção Bourne / POSIX para fazer a correspondência de padrões. [[...]]
é apenas ksh / bash / zsh (com variações).
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 .
Uma outra maneira compatível com POSIX seria usar awk
com 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 NR
seja adicionado sum
, resultando na contagem total de caracteres e no número total de novas linhas encontradas no arquivo. A length()
função awk
aceita um argumento que, por padrão, significa length($0)
que é a linha inteira atual.
printf 'a\nb' | awk '{ sum+=length } END { print sum+NR }'
deve imprimir 3, mas imprime 4.
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
wc
lê o último bloco do arquivo, caso tenha stat.st_size
sido apenas uma aproximação (como para Linux /proc
e /sys
arquivos). 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
O método mais rápido e mais simples (IMO) é:
bash_var=$(stat -c %s /path/to/filename)
du
e wc
respostas 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 .