我有一个文件,例如:~/cwd
。这个文件的内容是一行:
~/tmp
我想要将当前目录切换到(~/tmp)目录。我尝试使用以下命令:
> cd `cat ~/cwd`
并得到了:
-bash: cd: ~/tmp: No such file or directory
为什么相对路径失败了?当
~/cwd
的内容是绝对路径时 - 它可以工作。这不是相对路径的问题——这是因为shell评估模型在参数扩展之前进行了波浪线扩展。使用eval跳回到评估过程的开头会引入安全漏洞,因此如果确实需要支持此功能(我强烈反对这样做),则一个安全的实现(针对具有getent
命令的平台)应如下所示:
expandPath() {
local path
local -a pathElements resultPathElements
IFS=':' read -r -a pathElements <<<"$1"
: "${pathElements[@]}"
for path in "${pathElements[@]}"; do
: "$path"
case $path in
"~+"/*)
path=$PWD/${path#"~+/"}
;;
"~-"/*)
path=$OLDPWD/${path#"~-/"}
;;
"~"/*)
path=$HOME/${path#"~/"}
;;
"~"*)
username=${path%%/*}
username=${username#"~"}
IFS=: read _ _ _ _ _ homedir _ < <(getent passwd "$username")
if [[ $path = */* ]]; then
path=${homedir}/${path#*/}
else
path=$homedir
fi
;;
esac
resultPathElements+=( "$path" )
done
local result
printf -v result '%s:' "${resultPathElements[@]}"
printf '%s\n' "${result%:}"
}
...安全地从文件中读取路径,可以使用以下方法:
printf '%s\n' "$(expandPath "$(<file)")"
或者,一种更简单的方法是谨慎地使用 eval
:
expandPath() {
case $1 in
~[+-]*)
local content content_q
printf -v content_q '%q' "${1:2}"
eval "content=${1:0:2}${content_q}"
printf '%s\n' "$content"
;;
~*)
local content content_q
printf -v content_q '%q' "${1:1}"
eval "content=~${content_q}"
printf '%s\n' "$content"
;;
*)
printf '%s\n' "$1"
;;
esac
}
返回
~root而不是
/root。但如果我这样做
printf '%s\n' "$(expandPath ~root)"` 就能正常工作。 - Jahidset -x
开始跟踪,并注意到未使用的变量 assetsPath
:D... 感谢您的快速响应... - Jahideval
的安全隐患,这应该是被接受的答案。 - codeforester试试这个:
eval cd `cat ~/cwd`
‘~’需要由Shell扩展。eval使命令通过shell的命令处理运行,其中包括‘~’的扩展。
"cat ~/cwd
' 不行呢?cat ~/cwd
给出了一个字符串,'cat' 应该能够正确解释它。 - egor7$(rm -rf /)/cwd
,那么情况就非常糟糕了。 - Charles Duffy使用 eval
:
eval cd $(cat file)
comm=$(cat file); [[ ! "$comm" == *rm* ]] && eval cd "$comm"
? - fedorqui~
的情况并且放弃使用eval。 - Charles Duffycat
:eval cd "$(<~/cwd)"
eval
的可能后果,只能是别人的担心或看法。我的回答只是对他们答案的更新。 - konsoleboxeval
的细节的必要性,但我选择不这样做,因为我认为对于一个简单的问题来说并不足够必要。再次考虑在这种话题中的安全性只是一种观点。希望你不会因此得出我在这些问题上不谨慎的结论。我在SO上回答了许多使用eval的脚本,请尝试看看是否能找到其中的缺陷。当然,除了这个问题。 - konsolebox
~/cwd
仍然是一个绝对路径;~
只是当前用户主目录的绝对路径的简写。它适用于交互式使用,而不适用于脚本编写。如果您对文件有控制权(如果您甚至考虑使用eval
,那么您应该有控制权),那么您应该完整地写出目录名,这样cd $(< ~/cwd)
就可以工作了。 - chepner