如何在脚本中使用newgrp并在脚本退出后仍保留该组

18

我正在Solaris Box上运行脚本,具体为SunOS 5.7。我不是root用户。我试图执行一个类似以下脚本的脚本:

newgrp thegroup << FOO
source .login_stuff
echo "hello world"
FOO

脚本运行。问题是它返回到调用进程中,使我回到旧组而source .login_stuff没有被加载。我理解这种行为。我正在寻找的方法是留在子shell中。现在我知道我可以在脚本中添加xterm& (见下文)来实现,但是新建一个xterm并不理想。

将当前pid作为参数传递。

newgrp thegroup << FOO
source .login_stuff
xterm&
echo $1
kill -9 $1
FOO

我没有可用的sg。同时,newgrp是必须的。

8个回答

22

以下代码很好用,将以下代码复制到(Bourne或Bash)脚本的顶部:

### first become another group
group=admin

if [ $(id -gn) != $group ]; then
  exec sg $group "$0 $*"
fi

### now continue with rest of the script

在Linux上这很正常。但有一个注意点:包含空格的参数会被拆分开来。我建议使用env arg1='value 1' arg2='value 2' script.sh的方式传递它们(由于某种原因我无法使用$@使其工作)。


引号有帮助吗?例如在执行 sg nas_bio3 "$@" 时。 - Yauhen Yakimovich
3
当一个问题标记为Solaris时,我不知道为什么会接受Linuxen的答案。我处于同样的情况,而且我的Solaris系统中不存在"sg"。 - Jolta

11
newgrp命令只能在交互式Shell中有意义地使用,据我所知。实际上,我放弃了它...嗯,至少足够久以前,我写的替代品现在已经有资格在英国和美国投票了。
请注意,newgrp是一个特殊的“内置”于shell中的命令。严格来说,它是一个外部命令,但是shell内置了处理它的知识。shell实际上会执行该程序,因此你会立即得到一个新的shell。它也是一个setuid root程序。至少在Solaris上,newgrp似乎也会忽略SHELL环境变量。
我有许多程序可以解决 newgrp 旨在解决的问题。请记住,该命令早于用户同时属于多个组的能力(请参阅 Version 7 Unix 手册)。由于 newgrp 不提供执行后续命令的机制(与 susudo 不同),因此我编写了一个名为 newgid 的程序,它像 newgrp 一样是 setuid root 程序,允许您在不同组之间切换。它非常简单 - 只有 main() 和一组用于标准化错误报告的函数。要获取源代码,请联系我(first dot last at gmail dot com)。我还有一个更危险的命令叫做 'asroot',它允许我(但仅限于默认编译下的我)更彻底地调整用户和组列表。
asroot: Configured for use by jleffler only
Usage: 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 help

Option 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 numbers
Mnemonic for effective UID/GID:
    s is second letter of user;
    r is second letter of group

(这个程序已经发展壮大:如果我从头开始重做它,我会接受用户ID或用户名,而不需要不同的选项字母;对于组ID或组名也是如此。)

获取安装setuid root程序的权限可能会很棘手。由于多组设施的存在,现在有一些解决方法可用。可能有效的一种技术是在要创建文件的目录上设置setgid位。这意味着无论谁创建文件,该文件都将属于拥有目录的组。这通常可以实现您需要的效果 - 尽管我知道很少有人能始终使用它。


我认为那会起作用。我会给你发电子邮件并询问源代码(或者我的电子邮件是paulydavis@gmail.com)。我可以无限制地使用这个源代码吗?我之所以问这个问题是因为它是商业用途(尽管是内部使用)。这个答案是被接受的答案。 - Paul
Solaris 10的newgrp(1)(至少)保留了用户的shell,并确实检查$SHELL(我已经检查了OpenSolaris源代码)。 - Martin Carpenter

10
newgrp adm << ANYNAME
# You can do more lines than just this.
echo This is running as group \$(id -gn)
ANYNAME

...将输出:

This is running as group adm

请注意--确保你用反斜杠转义'$'。交互有些奇怪,因为它在执行其他组的shell之前甚至会扩展单引号。所以,如果你的主要组是“users”,而你想使用的组是“adm”,那么:

newgrp adm << END
# You can do more lines than just this.
echo 'This is running as group $(id -gn)'
END

..将输出:

This is running as group users

因为'id -gn'是由当前的shell运行,然后被发送到作为adm运行的shell中。无论如何,我知道这篇文章很古老了,但希望对某些人有用。


2
这对我来说根本没有任何作用。但是我在Ubuntu上,你能解释一下<<应该做什么,ANYNAME代表什么,以及END的含义吗? - Shardj
2
这似乎并没有回答问题,因为当脚本退出时,您仍然不会在adm组中。 - Preethi Vaidyanathan
1
@Shardj 我正在使用Ubuntu 20.04,这对我有效。ANYNAMEENDheredocs - 它们基本上允许轻松创建多行字符串,我相信。 - jxmallett

6

这个例子是基于plinjzaad的回答进行扩展的;它处理了包含空格的带引号参数的命令行。

#!/bin/bash
group=wg-sierra-admin
if [ $(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

我用这个来展示它的工作原理。
% ./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-admin
1:a b
2:c d e
3:f
4:g h
5:i j k
6:l m
7:n o
8:p
9:q
10:r
11:s
12:t
13:u v
14:w x y z

0

或许

exec $SHELL

这样行吗?


0

你可以使用 sh(或者你想要使用的任何 shell)代替 xterm&

或者你也可以考虑使用别名(如果你的 shell 支持),这样你就可以保持在当前 shell 的上下文中。


0
sudo su - [user-name] -c exit;

这应该能解决问题 :)


0
在一个脚本文件中,例如tst.ksh:
#! /bin/ksh
/bin/ksh -c "newgrp thegroup"

在命令行中:

>> groups fred
oldgroup
>> tst.ksh

>> groups fred
thegroup

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接