我写了一个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
为什么以及如何解决?
答案 0 :(得分:1)
以下是指用户主目录中的文件:
~/.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\/}"
这将测试以确保字符串在进行替换之前以~/
开头。