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

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

我正在编写Bash脚本,并且不能真正在系统上安装任何新软件。

我认为已经在使用:

 perl -e '@x=stat(shift);print $x[7]' FILE 

甚至:

 ls -nl FILE | awk '{print $5}' 

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

wc -c < filename (简称字数, -c打印字节数)是一个便携式POSIX解决scheme。 只有输出格式在平台上可能不一致,因为可能会预留一些空格(Solaris就是这种情况)。

不要忽略inputredirect。 当文件作为parameter passing时,文件名将在字节计数后打印。

我担心它不适用于二进制文件,但它在Linux和Solaris上都可以正常工作。 你可以用wc -c < /usr/bin/wc来试试。 此外,除非明确指定,POSIX实用程序保证处理二进制文件 。

我结束了写我自己的程序(真的很小),只显示大小。 更多信息在这里: 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 

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

尽pipedu通常会打印磁盘使用情况,而不是实际的数据大小,但是GNU coreutils du可以按字节打印文件的“外观大小”

 du -b FILE 

但它不能在BSD,Solaris,MacOS下运行…

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

 TEMP=( $( ls -ln FILE ) ) SIZE=${TEMP[4]} 

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

跨平台最快的解决scheme(只对ls使用单个fork(),不会计算实际字符,不会产生不需要的awk,perl等)。

在MacOS,Linux上testing – 可能需要对Solaris进行较小的修改:

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

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

注意:将遵循符号链接。

BSD拥有不同的GNU coreutils选项,但function类似。

 stat -f %z <file name> 

这适用于macOS (在10.12testing), FreeBSD , NetBSD和OpenBSD 。

您可以使用find命令来获取一些文件(在这里提取临时文件)。 然后,可以使用du命令,使用-h开关以可读的forms获取每个文件的文件大小。

find $HOME -type f -name "*~" -exec du -h {} \;

OUTPUT:

 4.0K /home/turing/Desktop/JavaExmp/TwoButtons.java~ 4.0K /home/turing/Desktop/JavaExmp/MyDrawPanel.java~ 4.0K /home/turing/Desktop/JavaExmp/Instream.java~ 4.0K /home/turing/Desktop/JavaExmp/RandomDemo.java~ 4.0K /home/turing/Desktop/JavaExmp/Buff.java~ 4.0K /home/turing/Desktop/JavaExmp/SimpleGui2.java~ 

你的第一个Perl例子对我来说看起来不合理。

正是出于这样的原因,我从编写shell脚本(使用bash / sh等)迁移到除了Perl中最平凡的脚本之外的所有东西。 我发现我不得不根据特定的需求来启动Perl,而且随着我越来越多的操作,我意识到使用Perl编写脚本可能是一个更强大的function(就语言和通过CPAN可用的各种库而言)和更有效的方式来实现我想要的。

请注意,其他shell脚本语言(例如python / ruby​​)无疑会有类似的function,您可能需要为您的目的进行评估。 我只讨论Perl,因为这是我使用和熟悉的语言。

那么du -s <file>呢?

如果你使用GNU fileutils的find

 size=$( find . -maxdepth 1 -type f -name filename -printf '%s' ) 

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

处理ls -n输出时,作为不可移植的shell数组的替代,可以使用位置参数,这些参数构成唯一的数组,并且是标准shell中唯一的局部variables。 将函数中位置参数的覆盖包裹起来,将原始参数保存到脚本或函数中。

 getsize() { set -- $(ls -dn "$1") && echo $5; } getsize FILE 

这根据当前IFS环境variables设置分割ln -dn的输出,将其分配给位置参数并回显第五个。 -d确保目录处理正确, -n确保用户名和组名不需要parsing,与-l不同。 而且,包含空格的用户名和组名在理论上可以打破预期的行结构; 他们通常被禁止,但这种可能性仍然使程序员停下来思考。

如果你的Solaris上有Perl,那就使用它。 否则,ls with awk是你的下一个最好的select,因为你没有stat或者你的find不是GNU find。

在我使用的Solaris中有一个技巧,如果你要求多个文件的大小,它只返回没有名字的总大小,所以包含一个空的文件,如/ dev / null作为第二个文件:

例如命令fileyouwant / dev / null

我不记得哪个大小的命令这对ls / wc / etc工作 – 不幸的是我没有一个solaris框来testing它。

在Linux上,你可以使用du -h $FILE ,在solaris上也能工作吗?

你试过了吗? awk'{print $ 1 * 1024}'。 这可能只是工作。