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

hau*_*d85 338 shell bash files

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

我如何将它分配给一个 bash 变量,以便我以后可以使用它?

b01*_*b01 327

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

stat --printf="%s" file.any
Run Code Online (Sandbox Code Playgroud)

人统计

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

在 bash 脚本中:

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

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

  • 在 MacOS 上,这有效:`stat -f%z myfile.tar` (12认同)
  • @haunted85 `stat` 是最直接的方法,假设您使用的是 Linux 或 Cygwin(`stat` 不是标准的)。`wc -c` 为 [Eugéne 建议](http://unix.stackexchange.com/questions/16640/how-do-i-can-get-the-size-of-a-file-in-a- bash-script/16668#16668) 是可移植的。 (8认同)
  • `stat:非法选项--c` (3认同)
  • @woohoo 您的提示会覆盖输出。`man stat` 表示 --printf 省略了尾随的换行符。使用 `--format` 或 `-c` 来查看输出。通过比较`stat --printf="%s" file.any 获得更多洞察力 xxd -` 到 `stat -c "%s" file.any | xxd -` (2认同)

Nem*_*emo 119

file_size_kb=`du -k "$filename" | cut -f1`
Run Code Online (Sandbox Code Playgroud)

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

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

ls有一个类似的问题,因为没有指定输出的确切格式,所以解析它的输出不能移植。 du -h也是一个 GNU 扩展。

在可能的情况下坚持使用可移植的结构,您将来会让某人的生活更轻松。也许是你自己的。

  • `du` 没有给出文件的大小,它给出了文件使用了多少空间的指示,这有细微的不同(通常 `du` 报告的大小是四舍五入到最接近的数字的文件大小块,其中块通常为 512B 或 1kB 或 4kB)。 (53认同)
  • 这应该是可接受的答案,使用 `--bytes` 或 `-b` 而不是 `-k`。 (18认同)
  • @Gilles,稀疏文件(即其中有孔的文件)报告的长度小于长度。 (7认同)
  • @fralau:OP 想要“将它分配给一个 bash 变量,以便他们以后可以使用它”,因此他们更有可能想要一个实际的数值,而不是人类可读的近似值。此外,`-h` 是一个 GNU 扩展;它不是 [标准](https://pubs.opengroup.org/onlinepubs/9699919799/utilities/du.html) (3认同)
  • 使用带有 `--apparent-size` 标志的 du **将返回更精确的大小**(如 man 所述:`打印表观大小,而不是磁盘使用情况;虽然表观大小通常较小,但由于到(“稀疏”)文件中的漏洞、内部碎片、间接块等`) (3认同)
  • `du`** 的 **`-h` ("human") 选项将为一般情况产生最合适的答案:```file_size=`du -h "$filename" | cut -f1``` ,因为它将根据需要显示 K(千字节)、M(兆字节)或 G(千兆字节)。 (2认同)
  • @AmedeeVanGasse - 不幸的是,`--bytes` 在 BSD Unix(例如 macos)上不可用。很重要,因为这个答案讨论的是 POSIX 兼容性。 (2认同)

小智 90

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

wc -c "$filename" | awk '{print $1}'
Run Code Online (Sandbox Code Playgroud)

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

$ wc -c somefile.txt
    1160 somefile.txt
Run Code Online (Sandbox Code Playgroud)

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

wc -c < "$filename"
Run Code Online (Sandbox Code Playgroud)

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

size="$(wc -c <"$filename")"
Run Code Online (Sandbox Code Playgroud)

  • `wc -c &lt;"$FILENAME"` 给出没有其他杂物的大小,因此 `size=$(wc -c &lt;"$FILENAME")`。 (38认同)
  • 还有一点:我刚刚测试了它,并且 `wc -c &lt; file` 似乎非常快,至少在 OS X 上是这样。我猜如果只指定了 -c,wc​​ 会尝试统计文件. (6认同)
  • @EdwardFalk:GNU `wc -c` 使用 `fstat`,然后寻找文件的倒数第二个块并读取最后一个 `st_blksize` 字节。显然 [这是因为例如 Linux 的`/proc` 和`/sys` 中的文件的统计大小仅为近似值](http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ wc.c#n246),并且 `wc` 想要报告实际大小,而不是统计报告的大小。我想 `wc -c` 报告与 `wc` 不同的大小会很奇怪,但是如果它是一个普通的磁盘文件并且它不在内存中,那么从文件中读取数据是不明智的。或者更糟的是,近线磁带存储... (4认同)
  • @keithpjolley:通过调用`fstat`。尝试运行 `strace wc -c &lt;/etc/passwd`,你可以看到它在做什么。 (2认同)

chb*_*own 61

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

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

所以现在一起:

stat -f%z myfile1.txt
Run Code Online (Sandbox Code Playgroud)

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


Sté*_*las 35

取决于你的意思是size

size=$(wc -c < "$file")
Run Code Online (Sandbox Code Playgroud)

将为您提供可以从文件中读取的字节数。IOW,它是文件内容的大小。然而,它将读取文件的内容(除非文件是常规文件或在大多数wc实现中作为优化的常规文件的符号链接)。那可能有副作用。例如,对于一个命名管道,哪些已经阅读不再可以再读一次的东西像/dev/zero或者/dev/random它们是无限大的,这将需要一段时间。这也意味着您需要read对该文件的权限,并且该文件的最后访问时间戳可能会被更新。

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

size=$(($(wc -c < "$file")))
Run Code Online (Sandbox Code Playgroud)

或者为了避免出现关于空算术表达式的错误,dash或者yash在不wc产生输出时(例如无法打开文件时):

size=$(($(wc -c < "$file") +0))
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

按时间顺序,有:

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

perl -le 'print((lstat shift)[7])' -- "$file"
Run Code Online (Sandbox Code Playgroud)

AIX 还有一个istat命令可以转储所有stat()(不是lstat(),所以不能处理符号链接)信息,你可以用它进行后处理,例如:

LC_ALL=C istat "$file" | awk 'NR == 4 {print $5}'
Run Code Online (Sandbox Code Playgroud)

(感谢@JeffSchaller帮助找出细节)。

tcsh

@ size = -Z $file:q
Run Code Online (Sandbox Code Playgroud)

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

早在 GNU 引入它的stat命令之前,同样可以用find带有-printf谓词的GNU命令来实现(已经在 1991 年):

find -- "$file" -prune -printf '%s\n'    # st_size of file
find -L -- "$file" -prune -printf '%s\n' # after symlink resolution
Run Code Online (Sandbox Code Playgroud)

但有一个问题是,如果$file-或 为find谓词(如!, (...),则它不起作用。

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

POSIXly,你可以这样做:

LC_ALL=C ls -dn -- "$file" | awk '{print $5; exit}'
Run Code Online (Sandbox Code Playgroud)

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

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

blockdev --getsize64 -- "$device_file"
Run Code Online (Sandbox Code Playgroud)

但是,您需要对此设备文件的读取权限。通常可以通过其他方式推导出大小。例如(仍在 Linux 上):

lsblk -bdno size -- "$device_file"
Run Code Online (Sandbox Code Playgroud)

除了空设备之外应该可以工作。

对所有工作的一种方法可查找文件(所以它包括常规文件,大多数块设备和某些字符设备)是打开文件,寻求结束:

对于命名管道,我们已经看到,有些系统(AIX,Solaris和HP / UX至少)使在管道缓冲区中的可用数据量stat()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"
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

这通常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"


小智 22

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

(
  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}'
Run Code Online (Sandbox Code Playgroud)

该脚本适用于许多 Unix 系统,包括 Linux、BSD、OSX、Solaris、SunOS 等。

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

此脚本有一个生产版本,提供更多帮助和更多选项:https : //github.com/SixArm/file-size


小智 10

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
Run Code Online (Sandbox Code Playgroud)


Dru*_*les 8

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

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

-rw-r--r-- 1 user owner 1985 2011-07-12 16:48 index.php
Run Code Online (Sandbox Code Playgroud)

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

  • @dabest1 从某种意义上说,在另一个 unix 中,它们的输出可能不同(在某些 unix 中是不同的),这是不可靠的。 (3认同)

小智 6

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

我更喜欢du -h filename,它以人类可读的格式为您提供大小。

  • 那或`stat -c "%s"` ;) (2认同)

oli*_*ren 5

在您可以委托给的 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
Run Code Online (Sandbox Code Playgroud)

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