Closed BourgeoisBear closed 2 weeks ago
A couple of questions: did you try starting rc as "rc -l" for each xterm? Not a perfect solution, but an adequate workaround. I do something similar on MacOS Terminal.
As for inheriting variables, did you try this one-liner? It may just work:
eval `{bash -l -c 'rc -c whatis'}
rc reports its environment variables quote-escaped, so it should be able to inherit from bash and then re-evaluate the assignments from backquote expansion. Try it?
xterm has the XTerm*loginShell
option for automatically forcing a login term, but I use st, which lacks that option.
The one-liner is almost there, but seems to drop newlines. That was why I went through the trouble of parsing env --null
.
Yes, ifs will get in your way.
Would you consider a pull request for an .rc_interactive
feature, or is this a not broke / don't fix?
One more suggestion: you can overload fn prompt
to run stuff in an interactive context. Something like (untested)
fn prompt {
if (!~ $interactive_init $pid) {
# initialize stuff
. $HOME/.rcrc
# synchronize state
interactive_init=$pid
}
}
But how do you get fn prompt
automatically sourced in the interactive context?
Shell functions are exported in the environment. You should be able to paste the quoted form into your bash profile.
export fn_prompt='{rc stuff}'
Relying upon bash to source rc funcs seems a bit wacky to me. fn prompt
will also have to be redefined in .rcrc
to configure the prompt under a login shell, which does not source the sh/bash environment.
I think it's actually the same shell function regardless. You can redefine it harmlessly. Exported to the environment from sh it doesn't really look wacky:
$ export fn_prompt='{if(!~ $interactive_init $pid){. $HOME^/.rcinit;interactive_init=$pid}}'
Closing as "won't fix" -- there's a super high bar for new features.
Thanks for the troubleshooting. As someone who has already been to this rodeo, do you think something like Go would be a decent language for writing a shell, or would the runtime just get in the way?
It may be worth experimenting with Go. It's a powerful language. But it doesn't support fork(2) out of the box (only fork+exec) so the runtime in that sense will get in the way. But maybe a new shell language which doesn't have the same sub-shell semantics of the common Unix shells would be doable in Go. Worth a try for sure.
Start here: https://github.com/mvdan/sh. I haven't tried it, but it's a POSIX shell written in Go.
I've looked at that one. It's very clean. Though it seems more like a testbed for the parser than a production shell.
I guess it's safe to assume that fork + exec is going to be more expensive than fork + twiddle a few bits + continue? They expose the syscall, but that is probably asking for trouble when the runtime gets partially-forked alongside everything else. exec.Cmd
might be good enough though, and would be somewhat cross-platform for free. Haven't been a unix user long enough to imagine cases where the fork()
behavior is indispensable, so may end up painting myself into a corner on that one if there is some common case where it is.
Here are the built-ins he's implemented so far if you're interested:
https://github.com/mvdan/sh/blob/7bd422f92937020ddf4519e47f8ea1bbf815a6d5/interp/builtin.go#L55
Fork+exec is the standard pattern for running a new command in the Unix environment. The shell is an exception. It allows fine control over subshells, which as you say are "fork + continue". The difference is not performance but rather things like the semantics of signal delivery. I'm afraid the shell is very tightly coupled to the syscall API surface area. By "emulating" that with a Go program using fork+exec and threads for everything else, you may indeed paint yourself into a corner.
Or perhaps not. If you forgo POSIX compliance, maybe you end up with a useful and usable shell. I have my doubts (without having tried to make anything like this myself) about making a true POSIX-compliant shell with Go.
I'm not sure if these are actual issues, or user-errors, but they are issues I've encountered when using rc as my login shell:
Scenario 1: Interactive Shell Under X11
X sources a number of scripts (
/etc/profile
,/etc/profile.d/*
,$HOME/.profile
,/etc/X11/Xsession
,/etc/X11/Xsession.d/*
) under the/bin/sh
interpreter. These generate an environment that rc inherits when run interactively. However, since rc only autoloads a script (.rcrc) when run as a login shell, rc-specific definitions have to be sourced manually.Result: System & user environments initialized, rc-specific definitions missing.
Possible solution: Just as bash has
.bashrc
and.bash_profile
, and zsh has.zshrc
and.zprofile
, have a non-login shell autoscript for rc (.rc_interactive
perhaps?).Scenario 2: Login Shell
Logging in via SSH or Linux console invokes
rc
as a login shell..rcrc
is sourced, but system and user init scripts from the aforementioned paths are not sourced, and are not source-able from rc due to language difference.Result: Outside of PAM/auth vars, system environment is largely missing, but rc-specific definitions are sourced.
Possible Solution: First snag & import environment vars from
/bin/sh -l
when running as a login shell. This is what I've done in my config, but having to copy paste 34 lines of rc script to preserve your POSIX environment doesn't feel right.Here is my amateur version of this solution: