16

less complains about my value of $TERM, whereas more doesn’t. Which would be fine except for the fact that more is less.

Originally I was puzzled by tools suddenly disliking my $TERM value (I thought I configured Tmux to use tmux as $TERM a few system restarts ago), but a bigger question just entered the room: how come two byte for byte identical binaries behave differently?

❯ less
WARNING: terminal is not fully functional
Missing filename ("less --help" for help)

❯ more
Missing filename ("less --help" for help)

❯ echo (which less) (which more)
/usr/bin/less /usr/bin/more

❯ ls -Al /usr/bin/less
-rwxr-xr-x  2 root  wheel  384848 May 13 06:29 /usr/bin/less*

❯ ls -Al /usr/bin/more
-rwxr-xr-x  2 root  wheel  384848 May 13 06:29 /usr/bin/more*

❯ openssl dgst -sha256 /usr/bin/less
SHA2-256(/usr/bin/less)= 8567f60723d396cb9c6e8d0a5f5206f321adbb2982d71e75cd6ec32be4256591

❯ openssl dgst -sha256 /usr/bin/more
SHA2-256(/usr/bin/more)= 8567f60723d396cb9c6e8d0a5f5206f321adbb2982d71e75cd6ec32be4256591

❯ echo $TERM
tmux

❯ tmux -V
tmux 3.3a

❯ echo $SHELL
/opt/local/bin/fish

This is in macOS. If it is some Mac-specific dark magic I will move this to Ask Different, of course.

1 Answer 1

25

The same program can behave differently if it is being run with different parameters: in your first command it receives argv[] = {"less", NULL} as the command-line argument array, while the second one calls it with argv[] = {"more", NULL}, with the 0th item in argv always being the program's own name (the "normal" args begin at 1).

This is sometimes used to create "multi-call" programs, most famously BusyBox which provides almost the entire /bin in small systems (e.g. in your Wi-Fi router).

If the 'less' program is invoked as more, its argument array will have argv[0] == "more", which enables "POSIX more(1) compatibility" code within Less. (For example, instead of looking for additional options in the LESS environment variable it instead looks for them in MORE.)

9
  • 1
    Aha! Totally forgot the fact that a program can inspect what binary it is called as. May 30, 2023 at 7:08
  • 6
    To be precise, it does not "inspect what binary it is called as"; it is accepting the name that the caller says it used. It can be faked or done wrong, it's up to the calling program. (And the path is not usually included.)
    – alexis
    May 30, 2023 at 12:44
  • 1
    @alexis: Interesting point; on Linux at least it is actually possible for a process to readlink("/proc/self/exe") and get a string like "/usr/bin/g++" or "/usr/bin/c++" which interestingly does match which hardlinked name it was invoked as. Not that this would be better, it's appropriate and expected that programs behave according to argv[0], as well as more portable to implement and not relying on a mounted /proc filesystem on Linux. May 30, 2023 at 23:08
  • 1
    Exactly. It is possible to find this out, but that's not what normally happens and it's not what this answer describes.
    – alexis
    May 31, 2023 at 8:35
  • 1
    It's a bit like /bin/sh being invoked with "-sh" in its argv[0]. There's no binary named -sh, the caller deliberately puts the dash there to indicate a "login shell". May 31, 2023 at 8:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .