我写了一个shell,如果存在,它将尝试从文件路径收集文件到当前目录:
collect_file() {
fpath=$1
echo $fpath
if [ -e $fpath ]; then
fname=`basename $fpath`
`cp $1 $fname`
retval=$?
if [ $retval == 0 ]; then
echo "Collect file '$fpath'"
else
echo "Error: fail to copy file '$fpath'"
fi
else
echo "Error: file '$fpath' not found"
fi
}
现在,如果我传递一个空值~/.gitconfig
,它将成功,但当我传递一一个字符串值"~/.gitconfig"
时,它将失败。
collect_file ~/.gitconfig # will succeed to copy the file
collect_file "~/.gitconfig" # will fail
显示:
# results for bare value
/Users/Xaree/.gitconfig
Collect file '/Users/Xaree/.gitconfig'
# results for string value
~/.gitconfig
Error: file '~/.gitconfig' not found
为什么以及如何修复?
以下是指用户主目录中的文件:
~/.gitconfig
相比之下,以下是指名为~
:的目录中的文件
"~/.gitconfig"
当shell执行波浪号扩展时,~/
被解释为主目录。当!
未被引用时,shell仅执行波浪号扩展。如果字符串被引用,那么~
只意味着~
,而不是其他意思。
示例
请注意,波浪号扩展仅针对以下三种语句中的一种执行:
$ echo "~/.bashrc"
~/.bashrc
$ echo ~"/.bashrc"
~/.bashrc
$ echo ~/".bashrc"
/home/john1024/.bashrc
强制波浪号展开
由shell实现的Tilde扩展提供了许多具有许多特殊情况的功能。我们可以使用eval
强制进行通用波浪号扩展,但这会引入许多安全问题。然而,就基本情况而言,我们可以安全地用$HOME/
替换变量中的~/
,如下所示:
fpath="${fpath/~//$HOME/}"
上面的问题是,即使字符串不是以~/
开头,它也会替换第一次出现的~/
。为了避免这种情况,我们可以使用:
[ "${fpath#~/}" != "$fpath" ] && fpath="${fpath/~//$HOME/}"
这将测试以确保字符串在进行替换之前以~/
开头。