获取文件或文件夹大小(以字节为单位)的 POSIX 兼容方法是什么?

获取文件或文件夹大小(以字节为单位)的 POSIX 兼容方法是什么?

根据 Open Group 规范,POSIXdu没有-b以字节为单位显示大小的选项。那么,获取文件或文件夹大小(以字节为单位)的 POSIX 兼容方法是什么?

答案1

du作为 GNU对 所做的近似操作-sb,您可以这样做:

cumulative_size() (
  export LC_ALL=C
  ret=0
  [ "$#" -gt 0 ] || set .
  for file do
    case $file in
      (/*) sanitized=$file;;
      (*) sanitized=./$file;;
    esac
    size=$(
      find "$sanitized" ! -type b ! -type c -exec ls -niqd {} + |
        awk '! seen[$1]++ {sum += $6}
             END {print sum}'
    )
    if [ -n "$size" ]; then
      printf '%s\t%s\n' "$size" "$file"
    else
      ret=1
    fi
  done
  exit "$ret"
)

像 GNU 一样,du我们尝试通过查看文件的 inode 编号(如 的第一个字段中报告的那样ls -ni)仅对文件进行一次计数,但由于我们没有设备编号无法ls报告,假设目录层次结构不跨越多个文件系统。

与此相反,du我们也只在每个文件参数中进行重复数据删除。

例如在:

cumulative_size dir dir

及其内容的累积磁盘使用情况dir会报告两次,每个文件中的文件仅计数一次,而 GNUdu -bs只会报告dir一次磁盘使用情况。

我们排除设备文件,因为ls -n不报告其大小。至少在 Linux 上,这不会产生任何影响,因为它们的大小总是报告为0.

find不能给出以以下开头-或名称与其谓词匹配的文件路径(也包括!, ...)。(在这里,我们通过在文件路径./不以/、so find !find -printbecomesfind ./!或开头的情况下添加前缀来解决这个问题find ./-print。假设没有find实现具有以 开头的谓词/。这意味着我们也不需要传递 to--ls标记其选项的结束。

我们使用ls -nnot 来ls -l避免将 uids/gids 解码为用户名或组名(这会很昂贵,并且还会导致带有空格的名称出现问题)。 POSIX 指定-o/-g选项来完全删除这些字段,但它们是可选的。

的输出ls -n仅在 C/POSIX 语言环境中指定。此外,文件路径是非空字节的任意序列,您只能将它们作为 C 语言环境中的文本进行处理,因此LC_ALL=C.

我们还使用它-q来确保文件名或符号链接目标中的换行符不会造成影响。

另请注意,由于完整路径传递给ls,我们无法处理任意深度的目录结构,因为一旦路径长度超过 PATH_MAX ,它将停止工作。

错误报告相当粗糙。如果任何计算的大小返回空,我们仅报告非零退出状态。因此,零退出状态并不能保证所有文件大小都已计算在内。

答案2

不幸的是, 的输出格式ls显然没有标准化。因此解析其输出可能不是最好的主意。

另一种符合 POSIX 标准的查找单个文件大小(以字节为单位)的方法是使用wc -c

-c将每个输入文件中的字节数写入标准输出。

来源:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/wc.html

$ printf %s 0123456789ABCDEF >sixteenbytestestfile  # example file of 16 bytes length
$ wc -c sixteenbytestestfile
16 sixteenbytestestfile

如果我们不将文件作为参数传递,而是通过标准输入传递,则输出中将省略文件名:

$ wc -c <sixteenbytestestfile
16

显然,某些系统在数字输出周围添加了一些空格。我们可以使用以下方法删除它算术扩展没有任何算术运算:

$ filesize="   123   "  # possible wc -c output
$ printf %s\\n "-$filesize-"
-   123   -
$ printf %s\\n "-$((filesize))-"
-123-

总之,这里是一个获取文件大小的简单函数的定义:

$ filesize() { printf %s\\n "$(($(wc -c <"$1")))"; }
$ filesize sixteenbytestestfile
16

相关内容