547

When assigning a user's secondary group list using:

# usermod -G <grouplist> <user>

is it possible to force this group assignment to take effect without logging out all running sessions?

This would be very useful in the situation where a Screen session exists with many running shells, as the entire session essentially needs to be destroyed to make the group assignment take effect.

I think I can change the user's primary group in a running shell using the newgrp command - is there some alternative that would work for secondary groups?

Ideally, I'd want something that would take effect in each shell without being run manually in every one, but failing that, maybe some way of forcing Screen to execute the same command in each.

wonea
  • 1,817
  • 1
  • 23
  • 42
Simon
  • 5,962
  • 3
  • 16
  • 13
  • I know that at least for some window / session managers it's possible to do this such that the session picks up the new group and it's available to any new processes started from the menus, panel buttons or whatever. I came here just now looking to find that again, so can't say just now how to do it, and it's probably specific to the window manager. – mc0e Nov 09 '15 at 14:27

16 Answers16

588

From inside a shell, you can issue the following command

su - $USER

id will now list the new group:

id
maxadamo
  • 103
  • 3
stivlo
  • 6,601
  • 2
  • 17
  • 8
  • 6
    I think this the best approach in many cases, but the original poster did want to update multiple shells within a screen session. This solution would have be be done from each shell. – Adrian Ratnapala Dec 13 '11 at 08:57
  • 4
    The original solution would also only fix a single shell session in screen. I just tested that. The reason this solution works is because you are spawning a complete new session rather than inheriting from the original environment. – Dror Feb 06 '14 at 05:24
  • 2
    You can make the command slightly more generic like so: `su - $USER` – bmaupin Mar 26 '15 at 22:32
  • 2
    This requires you to type a password though, which might be awkward/unwanted if you are trying to do it in lots of sessions. – Legooolas Apr 15 '16 at 13:20
  • 1
    Could you please explain what does this? Also would be great why is better or the differences with other solutions like `newgrp -` and `exec su -l $USER`. – Pablo A Jul 23 '17 at 17:32
  • The one below with exec is a bit better, doesn't create a subshell. – Gringo Suave May 01 '18 at 18:39
  • 1
    Note that you won't be able to run X applications without doing ``export DISPLAY=:0.0`` after ``su - $USER``. (Or replace ":0.0" with whatever ``echo $DISPLAY`` outputs.) – nijoakim Dec 19 '19 at 13:07
  • `su - your_login` is the most elegant and simple way. – Hermann Schwarz Jan 10 '20 at 09:01
  • This only works for the current shell you're in. As soon as you exit the shell, you loose the group setting again. I ended up just logging out and back in. Much faster TBH – smac89 Mar 29 '21 at 06:23
  • -1 since practically it switches into a different shel! - any custom env-vars eg. PATH for your venvs, XDISPLAY, SSH_CONNECTION, git-prompts, command-colors etc are all lost afterwards. – ankostis Dec 23 '22 at 11:59
  • @ankostis it's far from perfect, but if you cannot logout and log back it's a hack. and indeed ran into this issue this afternoon wondering why my `$DISPLAY` env var was not being set anymore. now i know. ...go joe. – ipatch Feb 03 '23 at 22:05
289

Horribly hacky, but you could use two layers of newgrp to achieve this for a particular group:

id -g

...will give you the current primary group ID. We'll call this orig_group for the purposes of this example. Then:

newgrp <new_group_name>

...will switch you to that group as the primary and add it to the list of groups returned by groups or id -G. Now, a further:

newgrp <orig_group_name>

...will get you a shell in which you can see the new group and the primary is the original one.

This is horrible and will only get you one group added at a time, but it has helped me out a couple of times to get groups added without logging out/in my whole X session (e.g. to get fuse added as a group to a user so that sshfs will work).

Notes:

  • This doesn't require you to type your password either, which su will

  • Each call to newgrp launches a new shell (as a child of the current shell)

  • The current shell can be "replaced" with the exec command

    exec newgrp <new_group_name>
    
  • Using exec will resolve the caching issue for the current branch of the pstree

    I.e. if you are logged in to a window manager, every new terminal you launch will be a child of an earlier branch than the one "corrected" by this exercise and will therefore inherit the cached gid map.

NotTheDr01ds
  • 17,574
  • 4
  • 44
  • 81
Legooolas
  • 5,730
  • 6
  • 27
  • 21
  • 3
    On Fedora I had to do `newgrp $USER` instead of `newgrp `. That means I didn't have to find my original primary group ID, so it's even easier than this solution. – Richard Turner Jan 03 '14 at 17:08
  • This also doesn't require a password, which su does. – Legooolas Jun 19 '15 at 08:07
  • 3
    I found it was sufficient to do `newgrp `. This was Ubuntu 14.04 – Edward Falk Mar 18 '16 at 21:42
  • 9
    @EdwardFalk right, but you don't (might not) want to leave that group as your primary... – mimoralea May 26 '16 at 22:08
  • For `new group name` I had to specify the group that was missing from the first `id`. – Raffi Oct 11 '16 at 07:58
  • This doesn't seem to work... `newgrp -` will resolve to a login that doesn't include the ``.. Are you sure this answer is still functional? – user3467349 Dec 15 '16 at 22:08
  • @user3467349 where does that dash `-` before `` come from? The command should be `newgrp ` <== notice, no dash – pepoluan Dec 16 '16 at 15:24
  • The `-` was a typo but your answer 100% doesn't work. – user3467349 Dec 27 '16 at 13:02
  • try it: `groupadd example_group; sudo usermod -aG example_group; original_group=$(id -gn); newgrp example_group; newgrp $original_group;` than look at the output of `groups`. `example_group` is not in there. – user3467349 Dec 27 '16 at 13:09
  • 7
    Note that each `newgrp` creates a new shell, so when you need to fully exit from your session you need to do "exit exit exit" to get all the way out (: – jwd Jan 04 '17 at 17:45
  • Didn't work on Ubuntu 18.04. Asked for password and failed. `newgrp docker` resulted in `newgrp: failed to crypt password with previous salt: Invalid argument`. su method below worked. – rickfoosusa Jul 31 '18 at 20:38
  • 2
    See https://stackoverflow.com/a/10080117/925978 for how to do this inside a script; you need heredocs. – crockeea May 01 '19 at 21:58
  • 11
    @jwd You can avoid `exit; exit; exit` you could use `exec` to replace the current shell like `exec newgrp new_group`, then `exec newgrp orig_group`. – Tacahiroy Sep 06 '19 at 06:41
  • 1
    On Ubuntu 20.x, I found the stock `newgrp` command would not accept the numeric user id returned by the stock `id -g` command, but it does accept the textual user name as returned by `id -gn`, or alternatively `$USER` in most cases. – bitoffdev Feb 08 '21 at 20:14
243

This nifty trick from this link works great!

exec su -l $USER

I figured I'd post it here as every time I forget how to do this, this is the first link that come up in google.

Rob W
  • 2,083
  • 2
  • 22
  • 23
jhaagsma
  • 2,604
  • 1
  • 13
  • 15
  • 31
    +1 for not putting the user in a subshell; you can logout/exit as usual with this. Also, if NOPASSWD: is set in /etc/sudoers, you can instead use `exec sudo su -l $USER` to avoid being prompted for password. – Ivan X Aug 09 '14 at 15:06
  • 32
    Be advised: you'll be asked for a sudo password. If you get it wrong, your terminal will close. – Tyler Collier Feb 26 '15 at 18:57
  • 1
    This only works for an interactive shell, If you try to put it in a bash.sh script as soon as this command is run the script will stop. On this related question, https://unix.stackexchange.com/questions/18897/problem-while-running-newgrp-command-in-script, Gilles points out that this is just the way Linux processes work. Ansible will let you refresh group but it only works for ssh connections not localhost https://stackoverflow.com/questions/26677064/create-and-use-group-without-restart For localhost I've worked around it by using EC2's Userdata to pre-add the group before my first login. – neoakris Dec 30 '19 at 04:15
  • Two notes: (1) After running this I could not open X applications in this shell [Archlinux, Surface Book 2]. (2) This only works for the current shell. Else it is a good solution. – errolflynn May 04 '20 at 20:55
  • -1 since practically it switches into a different shel! - any custom env-vars eg. PATH for your venvs, XDISPLAY, SSH_CONNECTION, git-prompts, command-colors etc are all lost afterwards. – ankostis Dec 23 '22 at 11:58
49

1. Getting a shell with the new group without logging out and in again

If you're only adding one group, I used the following:

exec sg <new_group_name> "newgrp `id -gn`"

This is a variation on Legooolas's two-layer newgrp trick, but it is in one line and doesn't require you to manually enter your primary group.

sg is newgrp but accepting a command to execute with the new group ID. The exec means that the new shell replaces the existing shell, so you don't need to "logout" twice.

Unlike using su, you don't need to type in your password. It also doesn't refresh your environment (other than adding the group), so you retain your current working directory etc.

2. Executing the command in all Screen windows in a session

The at command in Screen runs a command in whatever windows you specify (note this is a Screen command, not a shell command).

You can use the following command to send the command to all an existing Screen sessions:

screen -S <session_name> -X at \# stuff 'exec sg <new_group_name> "newgrp `id -gn`"^M'

Note the use of single quotes to preserve the backticks and get id to run in the Screen session, and the ^M to get Screen to hit 'enter' at the end of your command.

Note also that screen's stuff command simply types the command text on your behalf. Therefore something strange may happen if one of the screen windows has a half-written command at a command prompt or is running an application other than a shell (e.g. emacs, top). If this is an issue, I have some ideas:

  • To get rid of any half-written command, you can add "^C" to the start of the command.
  • To avoid running the command in an emacs window, etc, you could ask at to filter on window title etc (in the example above, I use "#", which matches all windows, but you can filter by window title, user, etc).

To run the command in a specific window (identified by window number), use the following:

screen -S <session_name> -p 0 -X stuff 'exec sg <new_group_name> "newgrp `id -gn`"^M'
tom
  • 111
  • 4
  • 4
    Really nice answer. Small correction: `sg` expects the command to be a single argument, and ignores further arguments (try `sg some_group echo test`). So ``sg new_group_name newgrp `id -gn` `` is actually equivalent to `sg new_group_name newgrp`. The reason it seems to work is that when `newgrp` is invoked with no arguments it uses the default group in /etc/passwd, which usually matches the current group. The fix is to quote the command: ``sg new_group_name "newgrp `id -gn`"`` – tom Mar 17 '20 at 06:21
  • 1
    @tom: if `newgrp` without arguments uses the default group, why bother with `newgrp $(id -gn)` at all? `sg new_group_name newgrp` is all that is needed, correct? – MestreLion Jun 05 '22 at 08:13
  • 1
    @MestreLion: The reason for `id -gn` is to preserve the user's current group ID in the case where the current group it is not the default group. In most cases the user's current group will be their default group, and in that case `sg newgrp` would be fine. – tom Jun 06 '22 at 09:12
  • 1
    @tom: wow, so that snippet "loads" a new group and then is careful enough to "revert" to the user's previously _current_ group? Sweet! Wish I could upvote more. Suggestion: replace backticks with `$()`, far easier to read and also standard on most (all?) shells – MestreLion Jun 06 '22 at 18:26
  • 1
    @MestreLion: Yes (like the double-newgrp trick from [Legooolas' answer](https://superuser.com/questions/272061/reload-a-linux-users-group-assignments-without-logging-out#345051)). I personally prefer `$()`, but some non-POSIX shells such as `tcsh` don't support it ([demo](https://tio.run/##K0kuzvj/PzU5I18hAUwmJSZnl2QmZxcrlOcXZSdwgQVVNMBUSn5OTmKRQlpiZk6x5v//AA)). I [suggested an edit](https://superuser.com/review/suggested-edits/1128315) to fix the issue with `sg`, but left the backticks to respect the author's preference. – tom Jun 09 '22 at 05:23
  • IMHO This really should be the accepted answer - it's the only suggestion which does **not** break (modify) your primary group (everyone suggesting `newgrp` seems to overlook this issue) _and_ also does **not** require entering a password. – jaimet Aug 12 '23 at 12:25
35

Using newgrp command solved problem for me:

newgrp <GroupName>

This blog post has detailed explanation.

Pablo A
  • 1,470
  • 13
  • 21
19

Groups are usually enumerated at login, there is no way I know of to force it to re-do group enumeration without logging out and back in again.

Many answers voted up here seem to use a workaround that invokes a new shell with fresh environment (same as logging in again). the parent shell and all other continuously running programs will generally not receive the new group membership until being re-invoked from a fresh shell usually after clean logout and login.

Mister_Tom
  • 574
  • 5
  • 11
  • Truthfully, I'm pretty sure that this isn't true - I'd found a way to do it before on a Linux box. However, for the life of me, I cannot remember what the command was. If I find it, I'll post it. Edit: Just found it, I'm posting it as an answer. –  Jan 30 '12 at 16:11
  • 3
    Thank you for pointing this out, this is also my understanding. Every other answer here simply opens a new shell, no matter whether it replaces one open shell or restarts screen or whatever. There is no magical panacea to issue a command or script and have every running session, including your X session, reflect the new group memberships. – scravy Sep 13 '19 at 09:30
13

You can do this.

Add as many groups as you want using usermod -G. Then, as the user with a running session, run newgrp - with just the '-' argument.

This reinitializes the group id to the default, but it will also set the secondary groups as well. You can verify this by running groups from the current session, before and after the usermod and the newgrp.

This has to be run from each open session - I don't know much about screen. However, if it's possible to iterate over all open sessions and run newgrp, you should be good. You won't have to worry about knowing the groups or the group IDs.

Best of luck to you.

Pete
  • 105
  • 3
4

To summarize:

exec newgrp <newlyaddedgroupname1>
exec newgrp <newlyaddedgroupname2>
...
exec newgrp -

Using 'exec' means replace the existing shell with the new shell started by the newgrp command (so exiting from the new shell logs you out).

The final newgrp - is needed to restore your normal primary group, so files you later create will have that as their group owner.

Note: The original poster's question was how to make newly-added groups visible in existing processes. The gpasswd and usermod commands don't affect existing processes; newly-added (or deleted!) groups appear in (disappear from) your account, i.e. in the /etc/group and /etc/gshadow files, but permissions for existing processes aren't changed. To remove permissions you have to kill any running processes; newgrp - will not re-read /etc/group and reset the group list; instead, it seems to just use the groups previously associated with the process.

jimav
  • 151
  • 3
  • By the way, `exec su - ` can be used to get a new login shell with groups set, but that won't work in scripts because a new shell will read commands from the terminal. You could use `su -c "command ..." ` to restart your script, but the resulting process has no controlling terminal and so an error will occur if a screen editor or other interactive command is attempted. – jimav Feb 10 '17 at 23:30
  • Why was this downvoted? Can someone explain what's bad about it, because it was what occurred to me and I think I like it best? – jasonmp85 Mar 08 '17 at 00:02
  • Gah, I voted it up before testing. `newgrp -` does _not_ replace the "primary group". Patrick Conheady's answer is the best one here, as it neither forks nor changes the primary group. – jasonmp85 Mar 08 '17 at 00:30
4

If you need to preserve your environment variables, try exec sudo -E -u "$USER" "$SHELL". exec replaces the current shell with the new one, -E preserves the environment, -u "$USER" changes user to yourself, and $SHELL specifies the shell is the command to use.

retnikt
  • 239
  • 2
  • 7
4

To respawn the terminal but keep GUI applications working, try exec su -p $USER. This preserves environment variables (including Xorg stuff) but reloads groups.

Alternatively remove exec to spawn a subshell instead of replacing the current shell.

nyanpasu64
  • 301
  • 2
  • 9
3

This does the trick if you have sudo and it can save you from entering your password one more time in some cases:

sudo su $USER
the
  • 2,751
  • 1
  • 26
  • 35
2

I couldn't get the newgrp command to work. I'm not sure if this depends on /etc/sudoers, but I normally have to type my password for sudo, and this worked without requiring my password:

[leo60228@leonix:~]$ groups
users wheel

[leo60228@leonix:~]$ sudo echo hi
[sudo] password for leo60228:
hi

[leo60228@leonix:~]$ sudo -k # reset sudo timeout

[leo60228@leonix:~]$ exec sudo -i -u $(whoami) # no password necessary

[leo60228@leonix:~]$ groups
users wheel docker
leo60228
  • 143
  • 1
  • 7
2

There are already a lot of correct answers, however this worked fine for me on Debian based systems:

sudo -s -u ${USER}

This command will do the job in a sudo environment.

The -sflag run the shell as configured in the in the /etc/passwd file.

abu_bua
  • 369
  • 5
  • 7
1

The accepted answer is correct, but it's only good for interactive shell, and won't work in scripts. To solve this I used this:

newgrp <GroupName> << END
my_command
END

This will open a new session with the updated groups, run the command, and then it will bring you back to the first session, where you still not in the group. This will allow you to create the group and use it in the same script.

Rea Haas
  • 121
  • 4
1

I had similar issue but also for not logged-in users. Restart of nscd didn't help, but executing this command did: nscd -i group. That should instruct nscd (caching daemon) to reload the groups file.

Marki555
  • 1,213
  • 12
  • 20
0

I needed to do this in a shell script (script adds current user to a group, runs later commands that require that group membership). The newgrp command is brittle in that it can only run a new shell rather than an arbitrary command (I want to re-run the current shell script with original commandline args).

Here's my solution, which uses lots of bash-isms: (note the surrounding script needs some sort of branch to only run this function if the required group is not currently active):

(note: the script implies that it ran sudo adduser $user docker, which means it could also just run sudo docker everywhere instead of docker but that was undesirable in this case)

# save these for later
ORIGINAL_ARGS=("$@")

# This function is a little insane. The problem is this: user running
# this script is not a member of docker group, but used 'sudo' to add
# themselves to group. Without logging out and back in, the only way
# to gain access to that group is via the 'newgrp' command, which
# unfortunately starts a new shell rather than an arbitrary command...
#
# Also, we're going to newgrp twice: first to add the new group and
# again to restore the original group (but the new group remains in
# the 'groups' output).
#
# So this horrendous hack dups stdin to fd3 for later. Then runs
# 'newgrp' piping in a script that runs 'newgrp' a second time, piping
# in another script that restores stdin from fd3 and execs the
# original command...
restart-newgrp-newgrp() {
  # dup original stdin to fd3
  exec 3<&0

  local group="$1"
  local command="$0"
  local arg
  for arg in "${ORIGINAL_ARGS[@]}"; do
    printf -v command "%s %q" "$command" "$arg"
  done

  # restore original stdin from fd3; also replace any single-quote in
  # command with '"'"' to embed it in a single-quoted string
  local script
  printf -v script "exec newgrp %q <<<'exec <&3-; exec %s'" "$(id -gn)" "${command//\'/\'\"\'\"\'}"

  exec newgrp "$group" <<<"$script"
}
Patrick
  • 101