[root@hoge tmp]# uname -a Linux hoge 3.10.0-957.5.1.el7.x86_64 #1 SMP Fri Feb 1 14:54:57 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux [root@hoge tmp]# ls -l /etc/services -rw-r--r-- 1 root root 670293 Jun 7 2013 /etc/services [root@hoge tmp]# declare -i fsize=`wc -c /etc/services` bash: declare: 670293 /etc/services: division by 0 (error token is "/services") [root@hoge tmp]# echo $fsize [root@hoge tmp]# wc -c /etc/services 670293 /etc/services [root@hoge tmp]# declare -i fsize=`wc -c /etc/services | gawk '{print $1}'` [root@hoge tmp]# echo $fsize 670293gawk まで呼び出すのがイマイチだなとは思っていたのですが、本日ふと思い立ち、調べてみたら先人の方が居られました。
https://ameblo.jp/archive-redo-blog/entry-10196055325.html
なるほど標準入力にリダイレクトすれば1コマンドで済むのですね。賢い方法と思いました。
[root@hoge tmp]# declare -i fsize=`wc -c < /etc/services` [root@hoge tmp]# echo $fsize 670293これからは、このパターンを使おうと思います。
ところで、wc というコマンド名からは、ファイルを全部読んでファイルサイズを得る動きをしそうに見えますが、そこは賢い実装になっており、-c オプション指定だと fstat(2) システムコールが利用され、ファイルを全部読み出すなどという非効率な振舞いにはならないようです。
[root@hoge tmp]# strace wc -c < /etc/services execve("/usr/bin/wc", ["wc", "-c"], [/* 46 vars */]) = 0 brk(NULL) = 0x1e76000 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf32f000 access("/etc/ld.so.preload", R_OK) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 fstat(3, {st_mode=S_IFREG|0644, st_size=90399, ...}) = 0 mmap(NULL, 90399, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7fa4cf318000 close(3) = 0 open("/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\340$\2\0\0\0\0\0"..., 832) = 832 fstat(3, {st_mode=S_IFREG|0755, st_size=2151672, ...}) = 0 mmap(NULL, 3981792, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7fa4ced42000 mprotect(0x7fa4cef04000, 2097152, PROT_NONE) = 0 mmap(0x7fa4cf104000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x1c2000) = 0x7fa4cf104000 mmap(0x7fa4cf10a000, 16864, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf10a000 close(3) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf317000 mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf315000 arch_prctl(ARCH_SET_FS, 0x7fa4cf315740) = 0 mprotect(0x7fa4cf104000, 16384, PROT_READ) = 0 mprotect(0x608000, 4096, PROT_READ) = 0 mprotect(0x7fa4cf330000, 4096, PROT_READ) = 0 munmap(0x7fa4cf318000, 90399) = 0 brk(NULL) = 0x1e76000 brk(0x1e97000) = 0x1e97000 brk(NULL) = 0x1e97000 fstat(0, {st_mode=S_IFREG|0644, st_size=670293, ...}) = 0 lseek(0, 0, SEEK_CUR) = 0 lseek(0, 0, SEEK_END) = 670293 fstat(1, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 0), ...}) = 0 mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7fa4cf32e000 write(1, "670293\n", 7670293 ) = 7 close(0) = 0 close(1) = 0 munmap(0x7fa4cf32e000, 4096) = 0 close(2) = 0https://ameblo.jp/archive-redo-blog/entry-10196055325.html exit_group(0) = ? +++ exited with 0 +++ [root@hoge tmp]#ということで、これがベストな方法に思いましたが、他にあるでしょうかね?
もちろん Perl/Python/Ruby等 の汎用スクリプト言語を呼べば同様のことが出来るけど、軽量に行うには wc -c < file がベストなのではと思っています。
2019-07-24追記
stat -c %s というのもありますが、当然 -c %s を解釈する処理の分だけ遅いに違いないと思っていましたが、一応実験してみました。
[root@hoge ~]# perf stat stat -c %s /etc/services 670293 Performance counter stats for 'stat -c %s /etc/services': 0.728356 task-clock (msec) # 0.749 CPUs utilized 2 context-switches # 0.003 M/sec 0 cpu-migrations # 0.000 K/sec 249 page-faults # 0.342 M/sec 2,528,856 cycles # 3.472 GHz 1,292,306 instructions # 0.51 insn per cycle 252,891 branches # 347.208 M/sec 11,528 branch-misses # 4.56% of all branches 0.000972916 seconds time elapsed [root@hoge ~]# perf stat wc -c < /etc/services 670293 Performance counter stats for 'wc -c': 0.599273 task-clock (msec) # 0.705 CPUs utilized 2 context-switches # 0.003 M/sec 0 cpu-migrations # 0.000 K/sec 219 page-faults # 0.365 M/sec 2,077,769 cycles # 3.467 GHz 1,043,855 instructions # 0.50 insn per cycle 202,792 branches # 338.397 M/sec 10,808 branch-misses # 5.33% of all branches 0.000849638 seconds time elapsed
0 件のコメント:
コメントを投稿