Description
Go has added several functions for determining the user's configuration:
os.UserCacheDir
in os: add func UserCacheDir() string #22536 (Go 1.11).os.UserHomeDir
in proposal: os: add UserHomeDir #26463 (Go 1.12).os.UserConfigDir
in proposal: os: add UserConfigDir #29960 (Go 1.13).
Closely related to this is getting the user's shell, which is very OS-dependent, and surprisingly tricky to accomplish (especially if cgo is not available, for example when cross-compiling). Go's behavior of falling back to parsing local files (e.g. /etc/passwd
) when cgo is not available has led to a number of bugs in applications (e.g. #24383, twpayne/chezmoi#65).
Being able to invoke the user's shell is useful in interactive applications (e.g. VSCode's interactive terminal), command line applications (e.g. chezmoi's cd command, or any application that launches a user-specified command on the user's behalf.
There are existing packages to do this, for example:
This proposal is concretely:
Add a os.UserShell
function that returns the current user's shell.
Optionally, the os.UserShell
function could return some indication of the level of confidence in the returned result (if the current user's shell could not be determined, maybe it makes sense to fall back to an OS-dependent default shell).
Activity
mvdan commentedon Oct 16, 2019
The
os.User*Dir
funcs are easy to use; you get a directory, so you can create more directories underneath. I'm not so sure how the API would be generally useful here.For example, if the API returns
/bin/sh
orcmd.exe
, how should one call that with any arguments in a portable way? Or is it only meant to be called with no arguments, to then be used interactively or with standard input?ianlancetaylor commentedon Oct 16, 2019
What is the use case here? When do you specifically want to run the user's shell?
The packages you point to seem to be looking in
/etc/passwd
for the shell, which seems to mean that if we added this functionality it should go in the os/user package, not the os package.rsc commentedon Oct 21, 2019
This seems too system specific.
Also, on Unix, you should use $SHELL, not /etc/passwd.
twpayne commentedon Oct 21, 2019
Handling responses:
The arguments can be supplied by the user, for example in any kind of hook ("when I do X, invoke my shell to do Y"). Interactive and/or standard input uses are also valid use cases, e.g. for any applications that provide an embedded shell.
The suggestion for putting it in the
os
package is for consistency with theos.User*Dir
functions. It would also fit in theos/user
package.The method used to determine the user's shell include:
getpwnam_r
library function, if available.getent
on Linux,dscl
on macOS)./etc/passwd
(on some systems, e.g. Termux, the current user doesn't have an entry).$SHELL
environment variable (assuming the user's environment is set up correctly).In short, this is a superficially simple function that hides a lot of system-specific underlying complexity from the caller.
ianlancetaylor commentedon Oct 22, 2019
Given that we need to call
getpwnam_r
, it must go in os/user, not os. I don't see any particular similarity toos.UserHomeDir
, etc., as those are all directories.ianlancetaylor commentedon Oct 22, 2019
That said, it's not clear that this needs to go into the standard library. The argument that programs will use the user's shell to execute scripts seems very special purpose, as that can only be done for scripts provided by the user. Why not just have the user provide the shell at the same time?
Also, https://golang.org/doc/faq#x_in_std .
twpayne commentedon Oct 22, 2019
OK for putting it in
os/user
.Go's standard library provides nearly all the functionality to ready the
/etc/passwd
and/etc/group
databases - with the exception of the user's shell. It could be argued that the user's shell is an even more fundamental attribute than say the user's config directory or cache directory.That all said, I do realize that the use cases for needing to know the user's shell are limited and so am happy if this proposal is closed unaccepted. Thank you for considering it.
rsc commentedon Oct 30, 2019
This seems too special purpose. It can be done outside the standard library.
It seems like a likely decline to me.
twpayne commentedon Oct 30, 2019
Ack for decline. Thank you for considering it :)
Closing this issue.