Skip to content

Track and use the "function name" for $0 in forked binaries #194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

jpco
Copy link
Collaborator

@jpco jpco commented Apr 19, 2025

Very picky, very niche change. Found while thinking about path-cache.es and a notion of "aliases" that I've been playing around with.

Here is a script which demonstrates the change.

# base case; normal %pathsearch behavior
let (fn-sh = ()) sh -c 'echo $0'

# case: fn-name = /path/to/bin
let (fn-sh = /bin/sh) sh -c 'echo $0'

let (ps = $fn-%pathsearch)
fn %pathsearch bin {
	# something to return arguments along with a path name from %pathsearch
	if {~ $bin print-dollar-0} {
		result <={$ps sh} -c 'echo $0'
	} {
		$ps $bin
	}
}

# case: `%pathsearch name` returns `/path/to/bin arg list`
print-dollar-0

At head this script prints (on my machine):

sh
/bin/sh
/usr/bin/sh

In this fork this script prints:

sh
sh
print-dollar-0

There are two effects going on here:

  • if we set fn-name = /path/to/bin, then running name will invoke /path/to/bin with $0 set to name.
  • if we redefine %pathsearch such that %pathsearch name returns /path/to/bin some args, then running name will invoke /path/to/bin some args with $0 set to name.

What's the use of this? Well, it makes having a "reasonable" value for $0 possible in more cases. For example, when using path-cache.es, at HEAD we get:

; bash -c 'echo $0'
bash
; bash -c 'echo $0'
/usr/bin/bash
; bash -c 'echo $0'
/usr/bin/bash

which is, IMO, less than ideal. With this change, it prints bash every time. In theory we could just modify path-cache.es to define fn-bash = %run /usr/bin/bash bash instead of what we have now, but that feels to me less like letting the user define the behavior they want and more like working around a defective default.

The part of the change to do with %pathsearch is a little more sketchy, since es doesn't actually make any promises about what should happen when your %pathsearch receives multiple arguments or returns values other than a single binary. But for something like my trial "aliasing" setup here:

let (ps = $fn-%pathsearch)
fn %pathsearch nm {
  if {!~ $#(alias-$nm(1)) 0} {
    nm = $(alias-^$nm(1)) $nm(2 ...)
  }
  let ((nm args) = $nm) {
    if {~ $nm (/* ./* ../*)} {
      result $nm $args
    } {
      result <={$ps $nm} $args
    }
  }
}

alias-ls    = ls -F   --color=auto
alias-grep  = grep    --color=auto
alias-egrep = grep -E --color=auto
alias-fgrep = grep -F --color=auto

this change allows the user to keep the $0 they typed into their terminal or script. (Technically the behavior above differs from other shells; in this setup egrep will be the $0, while other shells will use grep. Is that a dealbreaker?)

All this behavior here is a little subtle. For example, when we have fn ls {/bin/ls $*}, running ls invokes the binary with $0 as /bin/ls, not ls, because technically ls doesn't refer to /bin/ls but rather a lambda which just so happens to run /bin/ls. But I think it provides a fairly good balance of intuition in the simple case and control in the more complex one.

@jpco
Copy link
Collaborator Author

jpco commented Apr 20, 2025

Actually, with the fn-name = /path/to/bin part of the change, I don't think my alias thing is useful :) The following gives me exactly the values of $0 that I expect:

fn-ls = <={%whatis ls} -F --color=auto   # $0 = ls
fn-grep = <={%whatis grep} --color=auto  # $0 = grep
fn-egrep = grep -E   # $0 = grep
fn-fgrep = grep -F   # $0 = grep

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant