$ myvar="/path to/my directory"
$ sudo bash -c "cd $myvar"
在这种情况下,我该如何引用$myvar
以避免由于 值中的空格而导致分词myvar
?
答案1
没有分词(如在未加引号的扩展上分割变量的功能)在该代码中,as$myvar
不是未加引号的。
然而,存在一个命令注入漏洞,$myvar
在传递到 之前已展开bash
。所以它的内容被解释为bash代码!
那里的空格会导致多个参数被传递给cd
,而不是因为分词,但是因为它们将被解析为 shell 语法中的几个标记。值为 时bye;reboot
,将会重新启动!
在这里,您想要:
sudo bash -c 'cd -P -- "$1"' bash "$myvar"
(您将 的内容$myvar
作为该内联脚本的第一个参数传递;请注意如何为各自的 shell 引用$myvar
和$1
,以防止 IFS 分词(和通配符))。
或者:
sudo MYVAR="$myvar" bash -c 'cd -P -- "$MYVAR"'
$myvar
(您在环境变量中传递 的内容)。
当然,你不会通过运行获得任何有用的东西仅有的 cd
在内联脚本中(除了检查是否root
可以cd
进入那里)。据推测,您希望将该脚本放在cd
那里,然后在那里执行其他操作,例如:
sudo bash -c 'cd -P -- "$1" && do-something' bash "$myvar"
如果目的是能够sudo
进入cd
您无法访问的目录,那么这实际上是行不通的。
sudo sh -c 'cd -P -- "$1" && exec bash' sh "$myvar"
bash
将开始与其当前目录进行交互$myvar
。但该 shell 将作为root
.
你可以这样做:
sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash
要与当前目录进行非特权交互,但如果您首先$myvar
没有进入该目录的权限,则即使它是您当前的工作目录,您也将无法在该目录中执行任何操作。cd
$ myvar=/var/spool/cron/crontabs
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ ls
ls: cannot open directory '.': Permission denied
例外情况是如果您确实有搜索有权访问目录本身,但不能访问其路径的目录组成部分之一:
$ myvar=1/2
$ mkdir -p "$myvar"
$ chmod 0 1
$ cd 1/2
cd: permission denied: 1/2
$ sudo sh -c 'cd -P -- "$1" && exec sudo -u "$SUDO_USER" bash' sh "$myvar"
bash-4.4$ pwd
/home/stephane/1/2
bash-4.4$ mkdir 3
bash-4.4$ ls
3
bash-4.4$ cd "$PWD"
bash: cd: /home/stephane/1/2: Permission denied
严格来说,对于$myvar
like的值(字面意思),当然,在 shell$(seq 10)
扩展该命令替换时,会出现分词bash
root
答案2
新的(bash 4.4)引用魔法可以让你更直接地做你想做的事。根据更大的上下文,使用其他技术之一可能会更好,但它在有限的上下文中确实有效。
sudo bash -c "cd ${myvar@Q}; pwd"
答案3
如果您不能信任 的内容$myvar
,唯一合理的方法是使用 GNUprintf
创建它的转义版本:
#!/bin/bash
myvar=$(printf '%q' "$myvar")
bash -c "echo $myvar"
正如printf
手册页所说:
%q
ARGUMENT 以可重复用作 shell 输入的格式打印,并使用建议的 POSIX
$''
语法转义不可打印的字符。
答案4
Stéphane Chazelas 建议的绝对是做到这一点的最佳方法。我只是提供一个关于如何安全地使用参数扩展语法引用而不是使用sed
子进程的答案,就像 R.. 的答案一样。
myvar='foo \'\''"bar'
quote() {
printf "'%s'" "${1//\'/\'\\\'\'}"
}
printf "value: %s\n" "$myvar"
printf "quoted: %s\n" "$(quote "$myvar")"
bash -c "printf 'interpolated in subshell script: %s\n' $(quote "$myvar")"
该脚本的输出是:
value: foo \'"bar
quoted: 'foo \'\''"bar'
interpolated in subshell script: foo \'"bar