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

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

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

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

答案1

如果在 GNU 系统上,你最好的选择是:

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

人统计:

%s 总大小,以字节为单位

在 bash 脚本中:

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

注意:参见@chbrown 的回答了解如何stat在 BSD 或 macOS 系统上使用。

答案2

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

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

例如,Solaris 附带 bash,但不附带stat.所以这并不完全是假设。

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

尽可能坚持便携式结构,您将来会让人们的生活变得更轻松。也许是你自己的。

答案3

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

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

问题是wc它会添加文件名并缩进输出。例如:

$ wc -c somefile.txt
    1160 somefile.txt

如果您想避免仅仅为了获取文件大小计数而链接完整的解释语言或流编辑器,只需重定向文件中的输入,这样就wc永远不会看到文件名:

wc -c < "$filename"

最后一种形式可以与命令替换一起使用,以轻松获取您正在寻找的 shell 变量值,如所提到的吉尔斯以下。

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

答案4

取决于你的意思尺寸

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

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

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

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

或者避免在dashyashwc不产生输出时(例如当文件无法打开时)出现有关空算术表达式的错误:

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

ksh93具有wc内置功能(如果您启用它,您也可以将其调用为command /opt/ast/bin/wc),这使得它对于该 shell 中的常规文件最有效。

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

这些报告在索引节点中找到的信息。其中信息之一是st_size属性。对于常规文件,这就是内容的大小(在没有错误的情况下可以从中读取多少数据(这是大多数wc -c实现在优化中使用的内容))。对于符号链接,这是目标路径的大小(以字节为单位)。对于命名管道,根据系统的不同,它可以是 0 或管道缓冲区中当前的字节数。对于块设备也是如此,根据系统的不同,您会得到 0 或底层存储的字节大小。

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

按时间顺序排列,有:

  • IRIXstat(90 年代):

    stat -qLs -- "$file"
    

    返回( )st_size的属性或:$filelstat()

    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 中最有效的。

  • GNUstat(2001);自 2005 年以来也在 BusyBox 中,自 2013 年以来stat在 Toybox 中stat(都复制了 GNUstat接口):

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

    (请注意 的含义-L与 IRIX 或 相比是相反的zsh stat)。

  • BSDstat(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 引入其命令之前,使用 GNU命令及其谓词stat就可以实现相同的效果(早在 1991 年):find-printf

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

$file但有一个问题是,如果以-or开头find(例如!, (...),则该方法不起作用。

从版本 4.9 开始,可以通过将文件路径通过其 stdin 传递来解决这个问题,而不是作为参数:

printf '%s\0' "$file" |
  find -files0-from - -prune -printf '%s\n'

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

POSIXly,你可以这样做:

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

-n需要暗示-l所以后者不应该是必要的,但你会发现在某些 BSD 上,它是必要的)。

-L在符号链接解析后添加相同的内容。这不适用于设备文件,尽管第五个字段是设备主编号而不是大小。

对于块设备,stat()返回 0 的系统st_size通常有其他 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()s中可用st_size。有些(如 Linux 或 FreeBSD)则不然。

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

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

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

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

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

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

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

  • POSIXLY_CORRECT=1 ls -sd -- "$file" | awk '{print $1; exit}'
  • POSIXLY_CORRECT=1 du -s -- "$file"(不适用于包含其中文件的磁盘使用情况的目录)。
  • GNUfind -- "$file" -printf '%b\n'
  • zstat -L +block -- $file
  • GNUstat -c %b -- "$file"
  • BSDstat -f %b -- "$file"
  • perl -le 'print((lstat shift)[12])' -- "$file"

严格来说,70 年代早期版本的 UNIX,从 v1 到 v4 都有一个stat命令。它只是从索引节点转储信息并且不采取任何选项。它显然在 v5 (1974) 中消失了,大概是因为它对于ls -l.

相关内容