在过去,/bin/true并且/bin/false在外壳实际上脚本。
例如,在PDP / 11 Unix系统7中:
$ ls -la /bin/true /bin/false
-rwxr-xr-x 1 bin         7 Jun  8  1979 /bin/false
-rwxr-xr-x 1 bin         0 Jun  8  1979 /bin/true
$
$ cat /bin/false
exit 1
$
$ cat /bin/true
$  
如今,至少在中bash,true和false命令被实现为Shell内置命令。因此,在命令行和内部shell脚本中使用false和true指令时,默认情况下均不会调用可执行二进制文件bash。
从bash源头来看builtins/mkbuiltins.c:
char * posix_builtins [] =
    {
      “别名”,“ bg”,“ cd”,“命令”,“ ** false **”,“ fc”,“ fg”,“ getopts”,“职位”,
      “ kill”,“ newgrp”,“ pwd”,“ read”,“ ** true **”,“ umask”,“ unalias”,“ wait”,
      (字符*)NULL
    };
同样根据@meuh的评论:
$ command -V true false
true is a shell builtin
false is a shell builtin
因此,可以肯定地说true,false可执行文件主要存在于其他程序中。
从现在开始,答案将集中在Debian 9/64位软件包中的/bin/true二进制文件上coreutils。(/usr/bin/true运行RedHat。RedHat和Debian都使用了该   coreutils软件包,并分析了后者的编译版本)。
因为它可以在源文件中可以看出false.c,/bin/false被编译以(几乎)相同的源代码作为/bin/true,只是返回EXIT_FAILURE(1)代替,所以这个答案可以应用于这两个二进制文件。
#define EXIT_STATUS EXIT_FAILURE
#include "true.c"
由于两个大小相同的可执行文件也可以确认:
$ ls -l /bin/true /bin/false
-rwxr-xr-x 1 root root 31464 Feb 22  2017 /bin/false
-rwxr-xr-x 1 root root 31464 Feb 22  2017 /bin/true
las,答案的直接问题why are true and false so large?可能是,因为现在没有如此紧迫的理由来关心他们的最佳表现。它们对bash性能不是必不可少的,不再被bash(脚本)使用。
类似的评论适用于它们的大小,对于当今的硬件而言,26KB的微不足道。对于典型的服务器/桌面而言,空间已不再是多余的,它们甚至不再为使用false和使用相同的二进制文件而烦恼true,因为它只是在使用的发行版中进行了两次部署coreutils。
但是,本着问题的实质,为什么应该把这么简单和很小的东西变得如此大?
这些部分的实际分布情况/bin/true如下图所示;主代码+数据大约占26KB二进制文件中的3KB,相当于的大小的12%/bin/true。
true多年来,该实用程序确实获得了更多的临时代码,尤其是对--version和的标准支持--help。
但是,它不是那么大的(唯一的)主要理由,而是在动态链接(使用共享库)的同时,还具有作为coreutils二进制链接的静态库的二进制文件通常使用的通用库的一部分。用于构建elf可执行文件的元数据也占二进制文件的很大一部分,按照今天的标准,它是一个相对较小的文件。
答案的其余部分用于解释我们如何构建以下图表,详细说明/bin/true可执行二进制文件的组成以及如何得出该结论。
 

正如@Maks所说,二进制文件是从C编译的;根据我的评论,也可以确认它来自coreutils。我们直接指向作者git https://github.com/wertarbyte/coreutils/blob/master/src/true.c,而不是像@Maks一样的gnu git(相同的来源,不同的存储库-此存储库已被选中,因为它具有coreutils库的完整源代码)
我们可以在/bin/true此处看到二进制文件的各种构建块(来自的Debian 9-64位coreutils):
$ file /bin/true
/bin/true: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=9ae82394864538fa7b23b7f87b259ea2a20889c4, stripped
$ size /bin/true
    text       data     bss     dec     hex filename
   24583       1160     416   26159    662f true
那些:
- 文字(通常为代码)约为24KB  
- 数据(初始化变量,主要是字符串)约为1KB  
- bss(未初始化的数据)0.5KB  
在24KB中,大约1KB用于固定58个外部功能。
剩下的大约23KB的代码。下面我们将展示实际的主文件-main()+ usage()代码已编译约1KB,并说明了其他22KB的用途。
使用深入研究二进制文件readelf -S true,我们可以看到,虽然二进制文件为26159字节,但是实际的编译代码为13017字节,其余为各种数据/初始化代码。
但是,true.c这还不是全部,如果仅那个文件,则13KB似乎太多了。我们可以看到main()带有elf的外部函数中未列出的调用函数objdump -T true;存在的功能:
这些外部未链接的额外功能main()是:
- set_program_name()
- close_stdout()
- version_etc()
因此,我的第一个怀疑部分是正确的,尽管该库正在使用动态库,但是/bin/true二进制文件很大*因为它包含一些静态库*(但这不是唯一的原因)。
编译C代码通常不会使这种空间无法解决,效率低下,因此我最初的怀疑是不对的。
额外的空间几乎是二进制文件大小的90%,实际上是额外的库/ elf元数据。
在使用Hopper拆卸/反编译二进制文件以了解函数的位置时,可以看出true.c / usage()函数的已编译二进制代码实际上是833字节,而true.c / main()函数的已编译二进制代码是225字节。个字节,大约略小于1KB。嵌入在静态库中的版本函数逻辑约为1KB。
实际编译的main()+ usage()+ version()+ strings + vars仅占用大约3KB至3.5KB。
确实具有讽刺意味的是,由于上述原因,如此小而谦虚的公用事业规模越来越大。
相关问题:了解Linux二进制文件在做什么
true.c main()与令人反感的函数调用:
int
main (int argc, char **argv)
{
  /* Recognize --help or --version only if it's the only command-line
     argument.  */
  if (argc == 2)
    {
      initialize_main (&argc, &argv);
      set_program_name (argv[0]);           <-----------
      setlocale (LC_ALL, "");
      bindtextdomain (PACKAGE, LOCALEDIR);
      textdomain (PACKAGE);
      atexit (close_stdout);             <-----
      if (STREQ (argv[1], "--help"))
        usage (EXIT_STATUS);
      if (STREQ (argv[1], "--version"))
        version_etc (stdout, PROGRAM_NAME, PACKAGE_NAME, Version,  AUTHORS,  <------
                     (char *) NULL);
    }
  exit (EXIT_STATUS);
}
二进制文件各个部分的十进制大小:
$ size -A -t true 
true  :
section               size      addr
.interp                 28       568
.note.ABI-tag           32       596
.note.gnu.build-id      36       628
.gnu.hash               60       664
.dynsym               1416       728
.dynstr                676      2144
.gnu.version           118      2820
.gnu.version_r          96      2944
.rela.dyn              624      3040
.rela.plt             1104      3664
.init                   23      4768
.plt                   752      4800
.plt.got                 8      5552
.text                13017      5568
.fini                    9     18588
.rodata               3104     18624
.eh_frame_hdr          572     21728
.eh_frame             2908     22304
.init_array              8   2125160
.fini_array              8   2125168
.jcr                     8   2125176
.data.rel.ro            88   2125184
.dynamic               480   2125272
.got                    48   2125752
.got.plt               392   2125824
.data                  128   2126240
.bss                   416   2126368
.gnu_debuglink          52         0
Total                26211
输出 readelf -S true 
$ readelf -S true
There are 30 section headers, starting at offset 0x7368:
Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           PROGBITS         0000000000000238  00000238
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.ABI-tag     NOTE             0000000000000254  00000254
       0000000000000020  0000000000000000   A       0     0     4
  [ 3] .note.gnu.build-i NOTE             0000000000000274  00000274
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .gnu.hash         GNU_HASH         0000000000000298  00000298
       000000000000003c  0000000000000000   A       5     0     8
  [ 5] .dynsym           DYNSYM           00000000000002d8  000002d8
       0000000000000588  0000000000000018   A       6     1     8
  [ 6] .dynstr           STRTAB           0000000000000860  00000860
       00000000000002a4  0000000000000000   A       0     0     1
  [ 7] .gnu.version      VERSYM           0000000000000b04  00000b04
       0000000000000076  0000000000000002   A       5     0     2
  [ 8] .gnu.version_r    VERNEED          0000000000000b80  00000b80
       0000000000000060  0000000000000000   A       6     1     8
  [ 9] .rela.dyn         RELA             0000000000000be0  00000be0
       0000000000000270  0000000000000018   A       5     0     8
  [10] .rela.plt         RELA             0000000000000e50  00000e50
       0000000000000450  0000000000000018  AI       5    25     8
  [11] .init             PROGBITS         00000000000012a0  000012a0
       0000000000000017  0000000000000000  AX       0     0     4
  [12] .plt              PROGBITS         00000000000012c0  000012c0
       00000000000002f0  0000000000000010  AX       0     0     16
  [13] .plt.got          PROGBITS         00000000000015b0  000015b0
       0000000000000008  0000000000000000  AX       0     0     8
  [14] .text             PROGBITS         00000000000015c0  000015c0
       00000000000032d9  0000000000000000  AX       0     0     16
  [15] .fini             PROGBITS         000000000000489c  0000489c
       0000000000000009  0000000000000000  AX       0     0     4
  [16] .rodata           PROGBITS         00000000000048c0  000048c0
       0000000000000c20  0000000000000000   A       0     0     32
  [17] .eh_frame_hdr     PROGBITS         00000000000054e0  000054e0
       000000000000023c  0000000000000000   A       0     0     4
  [18] .eh_frame         PROGBITS         0000000000005720  00005720
       0000000000000b5c  0000000000000000   A       0     0     8
  [19] .init_array       INIT_ARRAY       0000000000206d68  00006d68
       0000000000000008  0000000000000008  WA       0     0     8
  [20] .fini_array       FINI_ARRAY       0000000000206d70  00006d70
       0000000000000008  0000000000000008  WA       0     0     8
  [21] .jcr              PROGBITS         0000000000206d78  00006d78
       0000000000000008  0000000000000000  WA       0     0     8
  [22] .data.rel.ro      PROGBITS         0000000000206d80  00006d80
       0000000000000058  0000000000000000  WA       0     0     32
  [23] .dynamic          DYNAMIC          0000000000206dd8  00006dd8
       00000000000001e0  0000000000000010  WA       6     0     8
  [24] .got              PROGBITS         0000000000206fb8  00006fb8
       0000000000000030  0000000000000008  WA       0     0     8
  [25] .got.plt          PROGBITS         0000000000207000  00007000
       0000000000000188  0000000000000008  WA       0     0     8
  [26] .data             PROGBITS         00000000002071a0  000071a0
       0000000000000080  0000000000000000  WA       0     0     32
  [27] .bss              NOBITS           0000000000207220  00007220
       00000000000001a0  0000000000000000  WA       0     0     32
  [28] .gnu_debuglink    PROGBITS         0000000000000000  00007220
       0000000000000034  0000000000000000           0     0     1
  [29] .shstrtab         STRTAB           0000000000000000  00007254
       000000000000010f  0000000000000000           0     0     1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  l (large), p (processor specific)
输出objdump -T true(在运行时动态链接的外部函数)
$ objdump -T true
true:     file format elf64-x86-64
DYNAMIC SYMBOL TABLE:
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __uflow
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 getenv
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 free
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 abort
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __errno_location
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strncmp
0000000000000000  w   D  *UND*  0000000000000000              _ITM_deregisterTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 _exit
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __fpending
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 textdomain
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fclose
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 bindtextdomain
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 dcgettext
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __ctype_get_mb_cur_max
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strlen
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.4   __stack_chk_fail
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 mbrtowc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strrchr
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 lseek
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 memset
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fscanf
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 close
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __libc_start_main
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 memcmp
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fputs_unlocked
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 calloc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 strcmp
0000000000000000  w   D  *UND*  0000000000000000              __gmon_start__
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.14  memcpy
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fileno
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 malloc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fflush
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 nl_langinfo
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 ungetc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __freading
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 realloc
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fdopen
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 setlocale
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __printf_chk
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 error
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 open
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fseeko
0000000000000000  w   D  *UND*  0000000000000000              _Jv_RegisterClasses
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 __cxa_atexit
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 exit
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 fwrite
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3.4 __fprintf_chk
0000000000000000  w   D  *UND*  0000000000000000              _ITM_registerTMCloneTable
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 mbsinit
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.2.5 iswprint
0000000000000000  w   DF *UND*  0000000000000000  GLIBC_2.2.5 __cxa_finalize
0000000000000000      DF *UND*  0000000000000000  GLIBC_2.3   __ctype_b_loc
0000000000207228 g    DO .bss   0000000000000008  GLIBC_2.2.5 stdout
0000000000207220 g    DO .bss   0000000000000008  GLIBC_2.2.5 __progname
0000000000207230  w   DO .bss   0000000000000008  GLIBC_2.2.5 program_invocation_name
0000000000207230 g    DO .bss   0000000000000008  GLIBC_2.2.5 __progname_full
0000000000207220  w   DO .bss   0000000000000008  GLIBC_2.2.5 program_invocation_short_name
0000000000207240 g    DO .bss   0000000000000008  GLIBC_2.2.5 stderr
               
              
command -V truenotwhich。它将输出:true is a shell builtin用于bash。