How do you use newgrp in a script then stay in that group when the script exits
The following works nicely; put the following bit at the top of the (Bourne or Bash) script:
### first become another groupgroup=adminif [ $(id -gn) != $group ]; then exec sg $group "$0 $*"fi### now continue with rest of the script
This works fine on Linuxen. One caveat: arguments containing spaces are broken apart. I suggest you use the env arg1='value 1' arg2='value 2' script.sh construct to pass them in (I couldn't get it to work with $@ for some reason)
The newgrp
command can only meaningfully be used from an interactive shell, AFAICT. In fact, I gave up on it about ... well, let's say long enough ago that the replacement I wrote is now eligible to vote in both the UK and the USA.
Note that newgrp
is a special command 'built into' the shell. Strictly, it is a command that is external to the shell, but the shell has built-in knowledge about how to handle it. The shell actually exec
's the program, so you get a new shell immediately afterwards. It is also a setuid root program. On Solaris, at least, newgrp
also seems to ignore the SHELL environment variable.
I have a variety of programs that work around the issue that newgrp
was intended to address. Remember, the command pre-dates the ability of users to belong to multiple groups at once (see the Version 7 Unix Manuals). Since newgrp
does not provide a mechanism to execute commands after it executes, unlike su
or sudo
, I wrote a program newgid
which, like newgrp
, is a setuid root program and allows you to switch from one group to another. It is fairly simple - just main() plus a set of standardized error reporting functions used. Contact me (first dot last at gmail dot com) for the source. I also have a much more dangerous command called 'asroot
' that allows me (but only me - under the default compilation) to tweak user and group lists much more thoroughly.
asroot: Configured for use by jleffler onlyUsage: asroot [-hnpxzV] [<uid controls>] [<gid controls>] [-m umask] [--] command [arguments] <uid controls> = [-u usr|-U uid] [-s euser|-S euid][-i user] <gid controls> = [-C] [-g grp|-G gid] [-a grp][-A gid] [-r egrp|-R egid]Use -h for more helpOption summary: -a group Add auxilliary group (by name) -A gid Add auxilliary group (by number) -C Cancel all auxilliary groups -g group Run with specified real GID (by name) -G gid Run with specified real GID (by number) -h Print this message and exit -i Initialize UID and GIDs as if for user (by name or number) -m umask Set umask to given value -n Do not run program -p Print privileges to be set -r euser Run with specified effective UID (by name) -R euid Run with specified effective UID (by number) -s egroup Run with specified effective GID (by name) -S egid Run with specified effective GID (by number) -u user Run with specified real UID (by name) -U uid Run with specified real UID (by number) -V Print version and exit -x Trace commands that are executed -z Do not verify the UID/GID numbersMnemonic for effective UID/GID: s is second letter of user; r is second letter of group
(This program grew: were I redoing it from scratch, I would accept user ID or user name without requiring different option letters; ditto for group ID or group name.)
It can be tricky to get permission to install setuid root programs. There are some workarounds available now because of the multi-group facilities. One technique that may work is to set the setgid bit on the directories where you want the files created. This means that regardless of who creates the file, the file will belong to the group that owns the directory. This often achieves the effect you need - though I know of few people who consistently use this.
This example was expanded from plinjzaad's answer; it handles a command line which contains quoted parameters that contain spaces.
#!/bin/bashgroup=wg-sierra-adminif [ $(id -gn) != $group ]then # Construct an array which quotes all the command-line parameters. arr=("${@/#/\"}") arr=("${arr[*]/%/\"}") exec sg $group "$0 ${arr[@]}"fi### now continue with rest of the script# This is a simple test to show that it works.echo "group: $(id -gn)"# Show all command line parameters.for i in $(seq 1 $#)do eval echo "$i:\${$i}"done
I used this to demonstrate that it works.
% ./sg.test 'a b' 'c d e' f 'g h' 'i j k' 'l m' 'n o' p q r s t 'u v' 'w x y z'group: wg-sierra-admin1:a b2:c d e3:f4:g h5:i j k6:l m7:n o8:p9:q10:r11:s12:t13:u v14:w x y z