如何在Bash脚本中结合变量使用realpath命令?
问题描述
在终端直接执行 realpath ~/test 会输出 /home/<user>/test,把路径存到变量里也能正常工作:
export REMOTE_DIR=~/test realpath $REMOTE_DIR
但写进脚本后就报错:
while true; do read -p "Enter the path of the Repository : " REMOTE_DIR if [ -d $(realpath $REMOTE_DIR) ]; then break; else echo "Path not found!! Please enter a valid path." fi done
错误提示:realpath: '~/test': No such file or directory。而且如果用引号包裹路径,比如 export REMOTE_DIR='~/test' 再执行 realpath $REMOTE_DIR,也会报同样的错。
另外,直接用 [ -d "$REMOTE_DIR" ] 判断输入的 ~/test 时,脚本也会输出“Path not found”。
问题根源
Bash 里的波浪号 ~ 只有在未被引号包裹且作为路径开头时,才会被自动展开成当前用户的家目录。但 read 命令读取的内容会原封不动保存,不会自动解析 ~;如果用单引号包裹 ~/test,引号会直接阻止 Bash 解析波浪号,导致 realpath 收到的就是字面量 ~/test,自然找不到对应的目录。
解决办法
方法1:手动展开波浪号
用 eval 命令解析变量里的波浪号(注意:eval 有安全风险,仅在你能完全信任输入内容的场景下使用):
while true; do read -p "Enter the path of the Repository : " REMOTE_DIR # 展开波浪号 expanded_dir=$(eval echo "$REMOTE_DIR") if [ -d "$expanded_dir" ]; then REMOTE_DIR="$expanded_dir" break else echo "Path not found!! Please enter a valid path." fi done
方法2:用 realpath 自带参数解析(推荐)
realpath 本身支持解析波浪号,结合 -e(即 --canonicalize-existing)参数可以同时验证路径是否存在:
while true; do read -p "Enter the path of the Repository : " REMOTE_DIR # 尝试解析路径并验证存在,丢弃错误输出 if expanded_dir=$(realpath -e "$REMOTE_DIR" 2>/dev/null); then REMOTE_DIR="$expanded_dir" break else echo "Path not found!! Please enter a valid path." fi done
这里 2>/dev/null 是把 realpath 的错误提示丢弃,避免干扰脚本的自定义提示。
方法3:简化输入要求
直接提示用户输入绝对路径(比如 /home/yourname/test)或者相对于当前目录的路径,跳过波浪号解析的问题,适合新手快速实现需求。
补充说明
你之前用 [ -d "$REMOTE_DIR" ] 判断失败,也是因为 REMOTE_DIR 里的 ~ 没被展开,Bash 会去寻找当前目录下名为 ~ 的子目录里的 test,显然不存在,所以判断不通过。
内容的提问来源于stack exchange,提问作者Trevor Philip

