5

我希望能够编写一个su_mt_user(当前)看起来像这样的函数:

su_mt_user() {
    su someuser -c "$*"
}

目标是能够像这样使用它:

su_mt_user mt-auth --stuff etc

这将以mt-auth --stuff etcuser 身份运行命令someuser。当前版本适用于此特定命令,但对于以下命令则失败:

some_filename_with_spaces="/home/user/hello there i like spaces in filenames.txt"
su_mt_user stat "$some_filename_with_spaces"

这失败并出现以下错误:

stat: cannot stat '/home/user/hello': No such file or directory
stat: cannot stat 'there': No such file or directory
stat: cannot stat 'i': No such file or directory
stat: cannot stat 'like': No such file or directory
stat: cannot stat 'spaces': No such file or directory
stat: cannot stat 'in': No such file or directory
stat: cannot stat 'filenames.txt': No such file or directory

我认为发生此错误是因为即使$some_filename_with_spaces正确地将其作为一个参数传递给su_mt_user函数,该函数也会将其扩展为多个参数"$*"

我也试过这个,反复试验:

su_mt_user() {
    su someuser -c "$0 $@"
}

但这也失败了(/usr/bin/stat: cannot execute binary file(什么?))

当然,stat "$some_filename_with_spaces"当前用户和someuser用户都按预期工作。

这看起来需要进行一些转义,但是 bash 知道如何做到这一点吗?需要手动替换吗?如果是这样,哪些字符需要转义?

4

1 回答 1

12

要通过函数将多个参数传递给命令,您需要"$@". "$@"特殊之处在于,即使它在双引号之间,单独的参数也会以不同的单词结尾,因此它们会按原样传递。这不同于$@$*不带引号,它会另外拆分每个包含空格的参数,并将每个结果单词解释为一个 glob 模式,以及 from "$*",它将所有参数合并为一个带有空格的参数。

有一个额外的皱纹,因为su不直接吃掉参数,它们通过一个外壳。的非选项参数su作为参数传递给sh -c,然后您需要为-c.

su_mt_user() {
    su someuser -c '"$0" "$@"' -- "$@"
}
于 2012-09-09T22:56:17.180 回答