使用 Sudo 执行 Bash 脚本函数

Bry*_*Kan 35 bash sudo function

我有一个脚本可以做很多不同的事情,其中​​大部分不需要任何特殊权限。但是,我在函数中包含的一个特定部分需要 root 权限。

我不希望整个脚本都以 root 身份运行,我希望能够在脚本中以 root 权限调用这个函数。必要时提示输入密码不是问题,因为它主要是交互式的。但是,当我尝试使用时sudo functionx,我得到:

sudo: functionx: command not found
Run Code Online (Sandbox Code Playgroud)

正如我所料,export没有任何区别。由于多种原因,我希望能够直接在脚本中执行该函数,而不是将其分解并作为单独的脚本执行。

有什么方法可以使我的函数对 sudo “可见”,而无需提取它,找到适当的目录,然后将其作为独立脚本执行?

该函数本身大约有一页长,包含多个字符串,一些是双引号的,一些是单引号的。它也依赖于在主脚本其他地方定义的菜单功能。

我只希望拥有 sudo ANY 的人能够运行该功能,因为它所做的一件事就是更改密码。

Wil*_*ill 28

我承认没有简单、直观的方法可以做到这一点,这有点老套。但是,你可以这样做:

function hello()
{
    echo "Hello!"
}

# Test that it works.
hello

FUNC=$(declare -f hello)
sudo bash -c "$FUNC; hello"
Run Code Online (Sandbox Code Playgroud)

或者更简单:

sudo bash -c "$(declare -f hello); hello"
Run Code Online (Sandbox Code Playgroud)

这个对我有用:

$ bash --version
GNU bash, version 4.3.42(1)-release (x86_64-apple-darwin14.5.0)
$ hello
Hello!
$
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Hello!
Run Code Online (Sandbox Code Playgroud)

基本上,declare -f将返回函数的内容,然后将其传递给bash -c内联。

如果要从 bash 的外部实例导出所有函数,请更改FUNC=$(declare -f hello)FUNC=$(declare -f).

编辑

要解决有关引用的评论,请参阅此示例:

$ hello()
> {
> echo "This 'is a' test."
> }
$ declare -f hello
hello ()
{
    echo "This 'is a' test."
}
$ FUNC=$(declare -f hello)
$ sudo bash -c "$FUNC; hello"
Password:
This 'is a' test.
Run Code Online (Sandbox Code Playgroud)

  • @cas `declare -f` 以一种可以被 bash 重新解析的方式打印出函数定义,因此 `bash -c "$(declare -f)"` * 确实* 正常工作(假设外壳是也bash)。你发布的例子显示它工作正常——引号被改变的地方是*在跟踪*中,因为bash以shell语法打印出跟踪,例如尝试`bash -xc 'echo "hello world"'` (5认同)
  • 优秀的答案。我实现了你的解决方案 - 我会注意到你可以从脚本中导入脚本本身,前提是你将它嵌套在一个条件中,以检查是否找到了“sudo yourFunction”(否则你会从递归中得到一个分段错误) (3认同)
  • 这只是偶然发生的,因为`echo "Hello!"` 实际上与`echo Hello!` 相同(即双引号对于这个特定的echo 命令没有区别)。在许多/大多数其他情况下,函数中的双引号可能会破坏 `bash -c` 命令。 (2认同)

Seb*_*bMa 12

我已经编写了自己的Sudobash 函数来执行此操作,它可以调用函数和别名:

function Sudo {
        local firstArg=$1
        if [ $(type -t $firstArg) = function ]
        then
                shift && command sudo bash -c "$(declare -f $firstArg);$firstArg $*"
        elif [ $(type -t $firstArg) = alias ]
        then
                alias sudo='\sudo '
                eval "sudo $@"
        else
                command sudo "$@"
        fi
}
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案,非常感谢@SebMa,这是一个出色的解决方案! (4认同)

cas*_*cas 5

“问题”是sudo清除环境(除了少数允许的变量)并将一些变量设置为预定义的安全值以防止安全风险。换句话说,这实际上不是问题。这是一个特点。

例如,如果您设置PATH="/path/to/myevildirectory:$PATH"并且sudo没有将 PATH 设置为预定义值,则任何未指定其运行的所有命令的完整路径名的脚本(即大多数脚本)将在/path/to/myevildirectory任何其他目录之前查找。将诸如lsgrep或其他常用工具之类的命令放入其中,您可以轻松地在系统上执行任何您喜欢的操作。

最简单/最好的方法是将函数重新编写为脚本并将其保存在路径中的某个位置(或在sudo命令行上指定脚本的完整路径- 除非sudo配置为允许您这样做,否则无论如何您都需要这样做以root身份运行任何命令),并使其可执行chmod +x /path/to/scriptname.sh

将 shell 函数重写为脚本就像将函数定义中的命令保存到文件中一样简单(没有function ..., {}行)。

  • 此外`sudo -E` 避免清除环境。 (2认同)