以便携式方式获取shell中的文件大小(以字节为单位)?

109 linux bash shell solaris

在Linux上,我使用stat --format="%s" FILE,但我有权访问的Solaris没有stat命令.那我应该怎么用?

我正在编写Bash脚本,无法在系统上安装任何新软件.

我考虑过已经使用过:

perl -e '@x=stat(shift);print $x[7]' FILE
Run Code Online (Sandbox Code Playgroud)

甚至:

ls -nl FILE | awk '{print $5}'
Run Code Online (Sandbox Code Playgroud)

但这些看起来都不合理 - 运行Perl只是为了获得文件大小?或者运行2个命令来做同样的事情?

Car*_*icz 198

wc -c < filename(字数统计,-c打印字节数)是一种便携式POSIX解决方案.只有输出格式在不同平台上可能不一致,因为某些空格可能会被预先添加(Solaris就是这种情况).

不要省略输入重定向.当文件作为参数传递时,文件名将在字节计数后打印.

我担心它对二进制文件不起作用,但它在Linux和Solaris上都可以正常工作.你可以尝试一下wc -c < /usr/bin/wc.此外,POSIX实用程序保证处理二进制文件,除非另有明确说明.

  • 或者只是`wc -c <file`如果你不想出现文件名. (67认同)
  • 但是,如果我没有弄错的话,管道中的`wc`必须`read()`整个流来计算字节数.`ls` /`awk`解决方案(和类似的)使用系统调用来获取大小,*应该是*线性时间(相对于O(大小)) (33认同)
  • 我不会用`wc -c`; 它看起来更整洁但是`ls` +`awk`更适合速度/资源使用.另外,我只是想指出你实际上还需要对`wc`的结果进行后处理,因为在某些系统上它会在结果之前有空格,你可能需要在进行比较之前去掉它. (6认同)
  • `wc -c`很棒,但是如果你没有对该文件的读访问权,它将无法工作. (3认同)
  • `stat` 和 `ls` 实用程序只是执行 `lstat` 系统调用并在不读取文件的情况下获取文件长度。因此,它们不需要读取权限并且它们的性能不依赖于文件的长度。`wc` 实际上打开文件并通常读取它,使其在大文件上表现更差。但是 [GNU coreutils wc](http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/wc.c) 在只需要常规文件的字节数时进行了优化:它使用 `fstat`和 `lseek` 系统调用来获取计数。请参阅其源代码中带有 `(dd ibs=99k skip=1 count=0; ./wc -c) &lt; /etc/group` 的注释。 (2认同)

小智 37

我最终编写了自己的程序(非常小)来显示大小.更多信息请访问:http://fwhacking.blogspot.com/2011/03/bfsize-print-file-size-in-bytes-and.html

在我看来,使用常见Linux工具的两种最干净的方法是:

$ stat -c %s /usr/bin/stat
50000

$ wc -c < /usr/bin/wc
36912
Run Code Online (Sandbox Code Playgroud)

但我只是不想输入参数或管道输出只是为了获得文件大小,所以我使用自己的bfsize.

  • 关键在于像我这样的人在Google中找到这个问题,并且`stat` _is_是他们的选择. (22认同)
  • 我正在开发一个嵌入式系统,其中`wc -c`在10 MB文件上占用4090毫秒而在"stat -c%s"占用"0"毫秒,所以我同意,即使它们不在,也可以使用替代解决方案回答提出的确切问题. (3认同)
  • "stat -c"不可移植/不接受MacOS上与Linux上相同的参数."wc -c"对于大文件来说会非常慢. (3认同)
  • 第一行问题描述表明stat不是一个选项,而且wc -c是现在一年多来的最佳答案,所以我不确定这个答案的重点是什么. (2认同)
  • stat也不可移植.`stat -c%s/usr/bin/stat``stat:非法选项 - c``用法:stat [-FlLnqrsx] [-f format] [-t timefmt] [file ...]` (2认同)

小智 25

即使du通常打印磁盘使用而不是实际数据大小,GNU coreutils du也可以以字节为单位打印文件的"表观大小":

du -b FILE
Run Code Online (Sandbox Code Playgroud)

但它不适用于BSD,Solaris,macOS,......

  • 在MacOS X上,`brew install coreutils`和`gdu -b`将达到同样的效果 (3认同)
  • 我更喜欢这种方法,因为 `wc` 需要在给出结果之前读取整个文件,`du` 是立即的。 (3认同)
  • POSIX 在 [`du` 基本原理](http://pubs.opengroup.org/onlinepubs/9699919799/utilities/du.html#tag_20_36_18) 的完全不同的上下文中提到了 `du -b`。 (3认同)

小智 13

最后我决定使用ls和bash数组扩展:

TEMP=( $( ls -ln FILE ) )
SIZE=${TEMP[4]}
Run Code Online (Sandbox Code Playgroud)

它不是很好,但至少它只有1个fork + execve,它不依赖于二级编程语言(perl/ruby​​/python/whatever)


Orw*_*ile 8

跨平台最快的解决方案(仅对ls使用单fork(),不尝试计算实际字符,不产生不需要的awk,perl等).

在MacOS,Linux上测试 - 可能需要对Solaris进行少量修改:

__ln=( $( ls -Lon "$1" ) )
__size=${__ln[3]}
echo "Size is: $__size bytes"
Run Code Online (Sandbox Code Playgroud)

如果需要,简化ls参数,并调整$ {__ ln [3]}中的偏移量.

注意:将遵循符号链接.


小智 8

BSD具有stat与GNU coreutils不同的选项,但具有相似的功能.

stat -f %z <file name> 
Run Code Online (Sandbox Code Playgroud)

这适用于macOS(在10.12 上测试),FreeBSD,NetBSDOpenBSD.


小智 7

在处理ls -n输出时,作为不可移植的 shell 数组的替代方法,您可以使用位置参数,它形成唯一的数组,并且是标准 shell 中唯一的局部变量。在函数中包装位置参数的覆盖以保留脚本或函数的原始参数。

getsize() { set -- $(ls -dn "$1") && echo $5; }
getsize FILE
Run Code Online (Sandbox Code Playgroud)

这会ln -dn根据当前IFS环境变量设置拆分 的输出,将其分配给位置参数并回显第五个。在-d确保目录得到妥善处理和-n用户名和组名不需要保证得到解决,不像-l。此外,包含空格的用户名和组名理论上可能会破坏预期的行结构;它们通常是不允许的,但这种可能性仍然让程序员停下来思考。


Pau*_*ce. 5

如果您find从 GNU fileutils使用:

size=$( find . -maxdepth 1 -type f -name filename -printf '%s' )
Run Code Online (Sandbox Code Playgroud)

不幸的是, 的其他实现find通常不支持-maxdepth,也不支持-printf。例如 Solaris 和 macOS 就是这种情况find