wc -c < filename
(代表单词计数,-c
打印字节计数)是一个可移植的POSIX解决方案。唯一可能不同于平台统一的是输出格式,因为某些空格可能会被添加(这是Solaris的情况)。
不要省略输入重定向符号。当文件作为参数传递时,文件名将在字节计数后被打印。
我很担心它不能用于二进制文件,但它在Linux和Solaris上都能正常工作。你可以用 wc -c < /usr/bin/wc
尝试一下。此外,POSIX实用程序可以保证处理二进制文件,除非明确地指定了其他内容。
wc -c < file
命令即可。 - cafwc
命令必须要读取整个数据流才能统计字节数。而 ls
/awk
等解决方案则使用了系统调用来获取文件大小,这应该是线性时间复杂度(与 O(文件大小) 相比)。 - jmtdwc -c
命令;虽然它看起来更整洁,但使用 ls
+ awk
命令可以更快速/节省资源。另外,我想指出的是,你实际上还需要对 wc
命令的结果进行后处理,因为在某些系统上它会在结果前有空白字符,你可能需要在进行比较之前去掉它们。 - Haravikkwc -c
命令很好用,但如果你没有文件的读取权限,它将无法工作。 - Silasstat
和 ls
工具只是执行 lstat
系统调用并获取文件长度,而不读取文件。因此,它们不需要读取权限,并且它们的性能不取决于文件的长度。相比之下,wc
实际上会打开并通常读取文件,在处理大文件时性能较差。但是 GNU Coreutils wc 在仅需要正常文件的字节数时进行了优化:它使用 fstat
和 lseek
系统调用来获取计数。请参见源代码中包含 (dd ibs=99k skip=1 count=0; ./wc -c) < /etc/group
注释。 - Palec我最终写了一个很小的程序来显示文件大小。更多信息在bfsize - 以字节打印文件大小 (仅此而已)中。
在我看来,使用常见的Linux工具有两种最干净的方法:
stat -c %s /usr/bin/stat
50000
wc -c < /usr/bin/wc
36912
但我不想输入参数或管道输出只是为了获得文件大小,因此我在使用自己的bfsize。
wc -c
命令在处理一个10 MB的文件时需要4090毫秒,而stat -c %s
命令只需"0"毫秒。因此,我认为即使这些解决方案并不能完全回答提出的问题,拥有备选方案也是有帮助的。请您注意,我的翻译不改变原意,且尽量简洁易懂。 - Robert Calhounstat -c %s /usr/bin/stat
stat:非法选项--c
用法:stat [-FlLnqrsx] [-f格式] [-t时间格式] [文件…]
- user1985657尽管du
通常打印磁盘使用情况而不是实际数据大小,但GNU Core Utilities的du
可以以字节形式打印文件的“表面大小”:
du -b FILE
brew install coreutils
е’Њ gdu -b
命令可以实现相同的效果。 - Jose Albandu
命令而不是 wc
命令,因为 wc
命令需要读取整个文件才能给出结果,而 du
命令则可以立即给出结果。 - CousinCocainelstat
调用,因此其性能不取决于文件大小。比 stat -c '%s'
更短,但对于文件夹的处理方式不同(打印其中每个文件的大小)。 - Palecdu
命令可以使用du -A -B1
来接近实现,但它仍然以1024B块的倍数打印结果。无法使其打印字节计数。即使在环境中设置BLOCKSIZE=1
也没有帮助,因为仍然使用512B块。 - Palecls -ln FILE | { read _ _ _ _ size _ && echo "$size"; }
不需要在管道的第二步骤中进行分叉,因为它只使用了内置命令,但是在 Linux 上,Bash 4.2.37 会分叉两次(尽管仍然只有一个 execve
)。 - Palecread _ _ _ _ size _ <<<"$(exec ls -ln /usr/bin/wc)" && echo "$size"
可以使用单个fork和单个exec,但它使用一个临时文件来进行here-string。通过将here-string替换为POSX兼容的here-document,可以使其可移植。顺便提一下,在子shell中使用exec
。如果没有这个,Bash会为子shell执行一个fork,然后为内部运行的命令执行另一个fork。这也是你在这个答案中提供的代码中的情况。 - Palecexec
。临时文件更糟,但这只是shell而已。试图如此严格地限制分叉数量绝对是过早优化,即万恶之源。可移植性、可读性和代码长度应该胜过像这样的小性能提升。如果需要优化一个工作中的shell脚本,你应该考虑重写它(或至少是其关键部分)到C语言。 - Palec-n
的情况下,-l
是多余的。引用 POSIX ls
manpage:*-n
: 打开 -l
选项,但在写入文件所有者或组时,分别写入文件的数字 UID 或 GID 而不是用户或组名。禁用 -C
、-m
和 -x
选项。* - Palec处理 ls -n
输出时,作为不太便携的 shell 数组的替代方案,您可以使用位置参数,它们形成了唯一的数组并且是标准 Shell 中唯一的本地变量。将位置参数的覆盖包装在函数中,以保留脚本或功能的原始参数。
getsize() { set -- $(ls -dn "$1") && echo $5; }
getsize FILE
IFS
环境变量设置分割ln -dn
的输出,将其分配给位置参数并回显第五个参数。 -d
确保目录被正确处理,而-n
确保不需要解析用户和组名称,与-l
不同。此外,包含空格的用户和组名称理论上可能会破坏预期的行结构。虽然它们通常被禁止,但这种可能性仍会使程序员停下来思考。请注意保留HTML标记。__ln=( $( ls -Lon "$1" ) )
__size=${__ln[3]}
echo "Size is: $__size bytes"
find
命令:size=$( find . -maxdepth 1 -type f -name filename -printf '%s' )
不幸的是,其他find
实现通常不支持-maxdepth
和-printf
。例如,Solaris和macOS的find
就是这种情况。
size=$(test -f filename && find filename -printf '%s')
。 - Palec-maxdepth
旨在防止 find
递归(因为 OP 需要替换的 stat
不是)。你的 find
命令缺少 -name
,而且 test
命令也不必要。 - Dennis Williamsonfind
会递归地搜索其参数以查找符合给定条件的文件。如果参数不是目录,则递归过程非常简单。因此,我首先测试 filename
是否真的是一个现有的普通文件,然后使用 find
打印其大小,因为此时 find
已经没有递归的对象了。 - Palecfind . -maxdepth 1 -type f -name filename -printf '%s'
只能工作,并且它仍然可能检查目录中的每个文件,这可能会很慢。最好使用(甚至更短!)find filename -maxdepth 1 -type f -printf '%s'
。 - Palecfind
命令获取一些文件集合(这里提取了临时文件)。然后您可以使用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~