it-swarm.cn

如何在bash脚本中获取文件的大小?

如何在bash脚本中获取文件的大小?

如何将其分配给bash变量,以便以后使用?

271
haunted85

如果在GNU系统上:

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

来自 man stat

%s总大小(以字节为单位)

在bash脚本中:

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

注意:有关如何在Mac OS X的终端中使用stat的信息,请参阅 @ chbrown的答案

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

使用stat的问题是它是GNU(Linux)扩展名。) du -kcut -f1 由POSIX指定,因此可移植到任何Unix系统。

例如,Solaris附带bash,但不附带stat。因此,这并非完全是假设。

ls存在类似的问题,因为未指定输出的确切格式,因此无法移植地解析其输出。 du -h也是GNU扩展名。

尽可能使用可移植的结构,将来您的生活会变得更轻松。也许是你自己的。

97
Nemo

您也可以使用“字数统计”命令(wc):

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

wc的问题在于它将添加文件名并缩进输出。例如:

$ wc -c somefile.txt
    1160 somefile.txt

如果要避免链接完整的解释语言或流编辑器只是为了获得文件大小计数,只需重定向文件中的输入,以使wc永远不会看到文件名:

wc -c < "$filename"

最后一种形式可以与命令替换一起使用,以轻松地获取您正在寻找的Shell变量值,如下面的 Gilles 所述。

size="$(wc -c <"$filename")"
79
Eugéne

BSD(macOS)stat具有不同的格式参数标志和不同的字段说明符。来自man stat(1)

  • -f format:使用指定的格式显示信息。有关有效格式的说明,请参见“格式”部分。
  • ...格式部分...
  • z:文件大小,以字节为单位。

所以现在在一起:

stat -f%z myfile1.txt

注意:有关如何在GNU/Linux系统上使用stat命令的信息,请参阅 @ b01的答案 。 :)

53
chbrown

取决于您的意思是size

_size=$(wc -c < "$file")
_

将为您提供可以从文件读取的字节数。 IOW,它是文件内容的大小。但是,它将读取文件的内容(除非该文件是常规文件或在大多数wc实现中作为常规文件的符号链接)。那可能会有副作用。例如,对于命名管道,已读取的内容将无法再读取,对于诸如_/dev/zero_或_/dev/random_之类的无限大小的文件,将需要一段时间。这也意味着您需要对该文件具有read权限,并且文件的上次访问时间戳可能会更新。

这是标准且可移植的,但是请注意,某些wc实现可能在该输出中包含前导空格。摆脱它们的一种方法是使用:

_size=$(($(wc -c < "$file")))
_

或为避免dash不产生任何输出(例如无法打开文件时)而导致yashwc中的空算术表达式出现错误:

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

_ksh93_内置wc(如果您启用了它,您也可以将其调用为_command /opt/ast/bin/wc_),这对于该Shell中的常规文件而言是最有效的。

各种系统都有一个名为stat的命令,该命令是stat()lstat()系统调用的接口。

这些报告信息在inode中找到。该信息之一是_st_size_属性。对于常规文件,这就是内容的大小(在没有错误的情况下,可以从其中读取多少数据(这是大多数_wc -c_实现在其优化中使用的内容))。对于符号链接,这是目标路径的大小(以字节为单位)。对于命名管道,取决于系统,它可以是0或管道缓冲区中当前的字节数。与块设备相同,在块设备中,取决于系统,您将获得0或基础存储的字节大小。

您不需要对该文件的读取权限即可获取该信息,而只需搜索对其链接到的目录的权限。

按照时间顺序,有:

  • IRIX stat (90年代):

    _stat -qLs -- "$file"
    _

    返回_st_size_(lstat())的_$file_属性,或:

    _stat -s -- "$file"
    _

    除_$file_是符号链接外,其他情况相同,在这种情况下,它是符号链接解析后文件的_st_size_。

  • zsh _ stat内置 (现在也称为zstat)在_zsh/stat_模块中(已加载_zmodload zsh/stat_)(1997):

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

    或存储在变量中:

    _stat -L -A size +size -- $file
    _

    显然,这是该Shell中最有效的。

  • GNU stat (2001);自2005年以来也在BusyBox stat中(复制自GNU stat)):

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

    (请注意,与IRIX或zshstat相比,_-L_的含义相反。

  • BSD stat (2002):

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

或者,您可以使用某些脚本语言的stat()/lstat()函数,例如Perl

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

AIX还有一个 istat命令 ,它将转储所有的stat()(不是lstat(),因此不适用于符号链接)信息,并且您可以使用以下方法进行后处理:

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

(感谢@JeffSchaller提供 帮助找出详细信息 )。

tcsh中:

_@ size = -Z $file:q
_

(符号链接解析后的大小)

在GNU)引入其stat命令之前,很早就可以通过GNU find)命令及其_-printf_实现相同的目标谓词(已于1991年):

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

但是,有一个问题是,如果_$file_以_-_开头或者是find谓词(如_!_,_(_...),则不起作用。

获取stat()/lstat()信息的标准命令是ls

POSIXly,您可以执行以下操作:

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

并在符号链接解析后添加_-L_相同。这对于设备文件不起作用,尽管5 字段是设备的主要编号,而不是大小。

对于块设备,stat()为_st_size_返回0的系统,通常具有其他API来报告块设备的大小。例如,Linux具有_BLKGETSIZE64_ ioctl(),并且大多数Linux发行版现在都带有blockdev命令,可以使用它:

_blockdev --getsize64 -- "$device_file"
_

但是,您需要对此设备文件具有读取权限。通常可以通过其他方式得出尺寸。例如(仍然在Linux上):

_lsblk -bdno size -- "$device_file"
_

应该可以正常工作,但空设备除外。

适用于所有可搜索文件(因此包括常规文件,大多数块设备和某些字符设备)的一种方法是打开文件并寻找结尾:

  • 使用zsh(在加载_zsh/system_模块之后):

    _{sysseek -w end 0 && size=$((systell(0)))} < $file
    _
  • 使用_ksh93_:

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

    要么

    _{ size=$(<#((EOF))); } < "$file"
    _
  • Perl

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

对于命名管道,我们已经看到某些系统(至少是AIX,Solaris,HP/UX)在stat()的_st_size_中提供了管道缓冲区中的数据量。有些(如Linux或FreeBSD)则没有。

至少在Linux上,您可以在打开管道后使用FIONREADioctl()(在读写模式下避免挂起):

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

但是请注意,尽管它不阅读管道的内容,但此处仅打开命名管道仍会产生副作用。我们正在使用fuser首先检查某些进程是否已打开管道以缓解这种情况,但这并不是万无一失的,因为fuser可能无法检查所有进程。

现在,到目前为止,我们仅考虑与文件关联的primary数据的大小。这没有考虑元数据的大小以及存储该文件所需的所有支持基础结构。

stat()返回的另一个inode属性是_st_blocks_。那就是用来存储文件数据(有时是一些元数据,例如Linux上ext4文件系统上的扩展属性)的512字节块的数量。这不包括索引节点本身,也不包括文件链接到的目录中的条目。

大小和磁盘使用情况不一定紧密相关,因为压缩,稀疏(有时是一些元数据),某些文件系统中的间接块之类的额外基础结构会对后者产生影响。

du通常用于报告磁盘使用情况。上面列出的大多数命令都可以为您提供该信息。

  • _POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'_
  • _POSIXLY_CORRECT=1 du -s -- "$file"_(不适用于包含其中文件的磁盘使用情况的目录)。
  • 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"
32
Stéphane Chazelas

该脚本结合了多种计算文件大小的方法:

(
  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}'

该脚本可在许多Unix系统上使用,包括Linux,BSD,OSX,Solaris,SunOS等。

文件大小显示字节数。它是表观大小,即文件在典型磁盘上使用的字节,没有特殊压缩,特殊稀疏区域或未分配的块等。

该脚本的生产版本在此处提供更多帮助和更多选项: https://github.com/SixArm/file-size

22
joelparkerhenderson

stat似乎用最少的系统调用来做到这一点:

$ 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
9
user150821

ls -l filename将为您提供有关文件的大量信息,包括文件大小,权限和所有者。

文件大小在第五列,以字节为单位显示。在下面的示例中,文件大小不到2KB:

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

编辑:这显然不如stat命令可靠。

8
Druckles

du filename将以字节为单位告诉您磁盘使用情况。

我更喜欢 du -h filename,以人类可读的格式提供尺寸。

5
Teddy

我找到了AWK 1班轮,它有一个错误,但我已将其修复。我还在TeraBytes之后添加了PetaBytes。

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] }')

考虑到不是每个系统上都有stat,因此几乎可以始终使用AWK解决方案。例; Raspberry Pi没有stat,但确实有awk

3
findrbot_admin

在可以委托给您的Shell脚本中创建小的实用程序函数。

示例

#! /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

基于@StéphaneChazelas的回答中的信息。

3
oligofren

另一种与POSIX兼容的方式是使用awk及其length()函数,该函数返回输入文件每一行中的字符长度(不包括换行符)。所以这样做

_awk '{ sum+=length } END { print sum+NR }' file
_

我们确保将NR添加到sum,从而得出文件中遇到的字符总数和换行符总数。 awk中的length()函数采用一个参数,默认情况下,该参数表示length($0),用于当前整行。

0
Inian