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

时间:2009-11-29 11:47:19

标签: linux bash shell solaris

在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个命令来做同样的事情?

15 个答案:

答案 0 :(得分:190)

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

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

我担心它对二进制文件不起作用,但它在Linux和Solaris上都可以正常工作。您可以使用wc -c < /usr/bin/wc进行尝试。此外,POSIX实用程序是guaranteed to handle binary files,除非另有明确说明。

答案 1 :(得分:35)

我最终编写了自己的程序(非常小)来显示大小。更多信息请访问: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

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

答案 2 :(得分:23)

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

du -b FILE

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

答案 3 :(得分:13)

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

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

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

答案 4 :(得分:8)

跨平台最快的解决方案(仅使用单个fork()用于 ls ,不会尝试计算实际字符,也不会生成不需要的awk,perl等)。

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

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

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

注意:将遵循符号链接。

答案 5 :(得分:7)

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

stat -f %z <file name> 

适用于macOS(在10.12测试),FreeBSDNetBSDOpenBSD

答案 6 :(得分:4)

当处理ls -n输出时,作为易于携带的shell数组的替代,您可以使用位置参数,它们构成唯一的数组,并且是标准shell中唯一的局部变量。在函数中包含位置参数的覆盖,以保留脚本或函数的原始参数。

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

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

答案 7 :(得分:3)

如果您使用GNU fileutils中的find

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

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

答案 8 :(得分:3)

您可以使用find命令获取一些文件集(此处提取临时文件)。然后,您可以使用du命令使用-h开关以人类可读的形式获取每个文件的文件大小。

  

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

输出:

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~

答案 9 :(得分:2)

你首先看到Perl的例子对我来说并不合理。

出于这样的原因,我从编写shell脚本(在bash / sh等中)迁移到编写Perl中除了最简单的脚本之外的所有脚本。我发现我必须针对特定要求启动Perl,而且随着我越来越多地这样做,我意识到在Perl中编写脚本可能更强大(就语言而言,可通过{提供的各种库) {3}})以及更有效的方式来实现我想要的目标。

请注意,其他shell脚本语言(例如python / ruby​​)无疑会有类似的功能,您可能需要根据自己的需要对其进行评估。我只讨论Perl,因为那是我使用的语言并且熟悉。

答案 10 :(得分:1)

我不知道 gnu gawk 的 filefuncs 扩展有多便携。基本语法是

$ time gawk -e '@load "filefuncs"; BEGIN { 
         
     fnL[1] = ARGV[ARGC-1];
     fts(fnL, FTS_PHYSICAL, arr); print ""; 

     for (fn0 in arr) { 
         print arr[fn0]["path"] \
           " :: "arr[fn0]["stat"]["size"]; }; 
    
     print ""; }' genieMV_204583_1.mp4

genieMV_204583_1.mp4 :: 259105690
real    0m0.013s

$ ls -Aln genieMV_204583_1.mp4
 
----------  1 501  20  259105690 Jan 25 09:31 
            genieMV_204583_1.mp4

该语法允许一次检查多个文件。对于单个文件,它是

$ time gawk -e '@load "filefuncs"; BEGIN {

      stat(ARGV[ARGC-1], arr); 
      printf("\n%s :: %s\n", arr["name"], \
           arr["size"]); }' genieMV_204583_1.mp4 

   genieMV_204583_1.mp4 :: 259105690
   real 0m0.013s

几乎没有任何增量节省。但不可否认,比直接上升略慢

$ time stat -f '%z' genieMV_204583_1.mp4 
259105690
real    0m0.006s (BSD-stat)

$ time gstat -c '%s' genieMV_204583_1.mp4 
259105690
real    0m0.009s (GNU-stat)

最后,一种将每个字节读入 awk 数组的简洁方法。此方法适用于二进制文件(正面或背面没有差异):

$ time mawk2 'BEGIN { RS = FS = "^$"; 
     FILENAME = ARGV[ARGC-1]; getline; 
     print "\n" FILENAME " :: "length"\n"; }' genieMV_204583_1.mp4 

genieMV_204583_1.mp4 :: 259105690
real    0m0.270s

$ time mawk2 'BEGIN { RS = FS = "^$"; 
   } END { print "\n" FILENAME " :: " \
     length "\n"; }'  genieMV_204583_1.mp4 

genieMV_204583_1.mp4 :: 259105690
real    0m0.269

但这不是最快的方法,因为您将所有内容都存储在 RAM 中。正常的 awk 范式在行上运行。问题是,对于像 mp4 这样的二进制文件,如果它们不完全以 \n 结尾,则 length + NR 方法的总和将多计一。下面的代码是一种通过明确使用最后一个 1 或 2 字节作为行分隔符 RS 的包罗万象的形式。

我发现使用 二进制文件2-byte 方法要快得多,而 1-byte 方法是一个典型的以换行符结尾的文本文件 .对于二进制文件,1 字节的文件可能会导致行拆分过于频繁并减慢速度。

但我们在这里接近吹毛求疵,因为读取 1.83GB txt 文件的每个字节都需要 mawk2,所以除非您正在处理大量数据,可以忽略不计。

尽管如此,正如其他人提到的,0.95 secs 仍然是迄今为止最快的,因为它是一个操作系统文件系统调用。

stat

(更新 mp4 的文件权限,因为 awk 方法需要它)

答案 11 :(得分:-3)

如果你的Solaris上有Perl,那么就使用它。否则,使用awk的ls是你的下一个最好的选择,因为你没有stat或你的发现不是GNU发现。

答案 12 :(得分:-3)

我使用的Solaris中有一个技巧,如果你要求多个文件的大小,它只返回没有名称的总大小 - 所以包括像/ dev / null这样的空文件作为第二个文件: / p>

例如     命令fileyouwant / dev / null

我无法记住哪个尺寸命令对ls / wc / etc有效 - 遗憾的是我没有solaris盒来测试它。

答案 13 :(得分:-4)

在Linux上你可以使用du -h $FILE,这对solaris也有效吗?

答案 14 :(得分:-6)

你试过duks | awk'{print $ 1 * 1024}'。这可能会奏效。