如何在 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
答案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")))
或者避免在dash
或yash
当wc
不产生输出时(例如当文件无法打开时)出现有关空算术表达式的错误:
size=$(($(wc -c < "$file") +0))
ksh93
具有wc
内置功能(如果您启用它,您也可以将其调用为command /opt/ast/bin/wc
),这使得它对于该 shell 中的常规文件最有效。
各种系统都有一个名为 的命令,它是或系统调用stat
的接口。stat()
lstat()
这些报告在索引节点中找到的信息。其中信息之一是st_size
属性。对于常规文件,这就是内容的大小(在没有错误的情况下可以从中读取多少数据(这是大多数wc -c
实现在优化中使用的内容))。对于符号链接,这是目标路径的大小(以字节为单位)。对于命名管道,根据系统的不同,它可以是 0 或管道缓冲区中当前的字节数。对于块设备也是如此,根据系统的不同,您会得到 0 或底层存储的字节大小。
您不需要文件的读取权限即可获取该信息,只需对其链接到的目录的搜索权限。
按时间顺序排列,有:
IRIX
stat
(90 年代):stat -qLs -- "$file"
返回( )
st_size
的属性或:$file
lstat()
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 中,自 2013 年以来stat
在 Toybox 中stat
(都复制了 GNUstat
接口):stat -c %s -- "$file" # st_size of file stat -Lc %s -- "$file" # after symlink resolution
(请注意 的含义
-L
与 IRIX 或 相比是相反的zsh
stat
)。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 引入其命令之前,使用 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"
(不适用于包含其中文件的磁盘使用情况的目录)。- 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"
严格来说,70 年代早期版本的 UNIX,从 v1 到 v4 都有一个stat
命令。它只是从索引节点转储信息并且不采取任何选项。它显然在 v5 (1974) 中消失了,大概是因为它对于ls -l
.