Eti*_*rot 5 bash arguments escaping function su
我希望能够编写一个su_mt_user
(当前)看起来像这样的函数:
su_mt_user() {
su someuser -c "$*"
}
Run Code Online (Sandbox Code Playgroud)
目标是能够像这样使用它:
su_mt_user mt-auth --stuff etc
Run Code Online (Sandbox Code Playgroud)
哪个会mt-auth --stuff etc
以用户身份运行该命令someuser
.当前版本适用于此特定命令,但对于以下命令失败:
some_filename_with_spaces="/home/user/hello there i like spaces in filenames.txt"
su_mt_user stat "$some_filename_with_spaces"
Run Code Online (Sandbox Code Playgroud)
此操作失败,并出现以下错误:
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
Run Code Online (Sandbox Code Playgroud)
我假设发生此错误$some_filename_with_spaces
是因为即使作为一个参数正确传递给su_mt_user
函数,该函数也会将其扩展为多个参数"$*"
.
我也试过这个,试错了:
su_mt_user() {
su someuser -c "$0 $@"
}
Run Code Online (Sandbox Code Playgroud)
但那也失败了(/usr/bin/stat: cannot execute binary file
(什么?))
当然stat "$some_filename_with_spaces"
,从当前用户和someuser
用户都可以按预期工作.
这看起来像是需要做一些逃避,但是bash知道如何做到这一点吗?是否需要手动替代?如果是这样,哪些角色需要转义?
Gil*_*il' 11
要通过函数将多个参数传递给命令,您需要"$@"
."$@"
特别之处在于即使它在双引号之间,单独的参数也以不同的词结尾,所以它们完全按原样传递.这与引号不同$@
或$*
不引用,它们会另外将每个参数拆分为包含空格并将每个结果单词解释为glob模式,并且从中"$*"
将所有参数合并为单个参数,其间包含空格.
还有一个额外的皱纹,因为su
不直接吃论点,他们通过壳.非选项参数su
作为参数传递给sh -c
,然后您需要一个适当的命令-c
.
su_mt_user() {
su someuser -c '"$0" "$@"' -- "$@"
}
Run Code Online (Sandbox Code Playgroud)