我编写了一个脚本,用于切换到root或在没有密码的情况下作为root运行命令。我编辑了我的/etc/sudoers文件,这样我的用户matt就可以在没有密码的情况下运行/bin/su。这是我的剧本的内容:
matt: ~ $ cat ~/bin/s
#!/bin/bash
[ "$1" != "" ] && c='-c'
sudo su $c "$*"如果没有参数--简单地说是s --它基本上会调用sudo su,它在没有密码的情况下进入根目录。但是如果我放置参数,$c变量等于"-c",这使得su执行一个命令。
它很好,除了当我需要使用空间的时候。例如:
matt: ~ $ touch file\ with\ spaces
matt: ~ $ s chown matt file\ with\ spaces
chown: cannot access 'file': No such file or directory
chown: cannot access 'with': No such file or directory
chown: cannot access 'spaces': No such file or directory
matt: ~ $ s chown matt 'file with spaces'
chown: cannot access 'file': No such file or directory
chown: cannot access 'with': No such file or directory
chown: cannot access 'spaces': No such file or directory
matt: ~ $ s chown matt 'file\ with\ spaces'
matt: ~ $ 我怎么才能解决这个问题?
另外,$*和$@有什么区别?
发布于 2011-04-27 23:58:24
啊,引用的乐趣。通常,@John建议的方法将适用于此:使用"$@",它不会试图解释(并被)参数中的空格和其他有趣的字符所迷惑。但是,在本例中,这是行不通的,因为su的-c选项希望整个命令作为单个参数传递,然后它将启动一个解析命令的新shell (包括被空格等弄糊涂)。为了避免这种情况,实际上需要重新引用要传递给su -c的字符串中的参数。bash的printf内置器可以做到这一点:
#!/bin/bash
if [ $# -gt 0 ]; then
sudo su -c "$(printf "%q " "$@")"
else
sudo su
fi让我来谈谈这里发生的事情:
运行类似于s chown matt file\ with\ spaces
printf "%q " "$@"命令,它将"$@"替换为脚本的参数,参数完全中断)。这相当于printf "%q " "chown" "matt" "file with spaces".printf将格式字符串"%q“解释为”以引号形式打印每个剩馀的参数,并在其后面加上空格“。它打印:"chown matt file\ with\ space ",本质上是重新构造原始命令行(它在末尾有一个额外的空间,但这不是problem).$()构造周围有双引号,所以它将被视为sudo的单个参数)。这相当于运行sudo su -c "chown matt file\ with\ spaces ".sudo运行su,并传递它获得的参数列表的其余部分,包括完全转义的command.su运行一个shell,它还传递其参数列表的其余部分。-c:chown matt file\ with\ spaces。在正常的解析过程中,它会将未转义的空间解释为参数之间的分隔符,将转义的空间解释为参数的一部分,它将忽略末尾的额外空间。chown,参数为"matt“和"file”。这符合你的预期。bash解析不是很麻烦吗?
发布于 2011-04-28 00:14:09
"$*"收集所有位置参数($1、$2、…)变成一个单词,用一个空格分隔(更一般地说,是$IFS的第一个字符)。注意,在shell术语中,单词可以包含任何字符,包括空格:"foo bar"或foo\ bar解析单个单词。例如,如果有三个参数,那么"$*"就相当于"$1 $2 $3"。如果没有参数,那么"$*"就相当于"" (一个空单词)。
"$@"是一种特殊的语法,它扩展到位置参数列表,每个参数都在自己的单词中。例如,如果有三个参数,那么"$@"就相当于"$1" "$2" "$3"。如果没有参数,那么"$@"就等于什么都没有(空列表,没有一个单词为空的列表)。
"$@"几乎总是您想要使用的,而不是"$*",或者没有引号的$*或$@ (最后两个完全等价,并执行文件名生成(a.k.a )。(所有位置参数上的单词分裂)。
还有一个问题,就是su除了一个shell命令作为-c的参数外,还传递了多个单词。您已经有了a detailed explanation of getting the quoting right,但是让我就如何正确处理它提供一些建议,这就避免了双重引用问题。关于https://unix.stackexchange.com/questions/3063/how-do-i-run-a-command-as-the-system-administrator-root和su的更多背景信息,您也可以参考sudo。
sudo已经以根用户的身份运行了一个命令,因此不需要调用su。如果您的脚本没有参数,您可以直接运行一个shell;除非您的sudo版本很旧,否则有一个选项:sudo -s。所以你的脚本可以是:
#!/bin/sh
if [ $# -eq 0 ]; then set -- -s; else set -- -- "$@"; fi
exec sudo "$@"(其他部分是处理以-开头的命令的罕见情况。)
不过,我不想看这么短的剧本。以根用户身份运行命令是不寻常的,而且风险很大,因此输入三个额外的字符不应该是一个问题。将shell作为根运行甚至更不寻常,风险更大,当然还需要另外六个字符。
https://stackoverflow.com/questions/5809783
复制相似问题