Bash脚本重复拼接DOWNLOAD_DIR路径找不到tar.gz文件如何解决
问题产生原因
- 路径重复拼接的核心错误:
原脚本中for f in $(ls ${DOWNLOAD_DIR}/*.tar.gz)的写法,ls返回的结果已经是包含DOWNLOAD_DIR前缀的完整路径(比如示例中返回的是data/colabfold_envdb_202108.tar.gz),后续执行tar命令时又再次拼接了${DOWNLOAD_DIR}/${f},相当于把路径前缀加了两次,最终生成了重复的data//data//xxx.tar.gz错误路径。 - 原写法还存在两个隐藏问题:
- 用
$(ls ...)遍历文件属于不安全写法,当文件名包含空格、换行符或特殊字符时,会出现解析错误 - 你调整后的代码仍存在变量引用错误:
BASENAME="$(basename {f%%.*})"中{f%%.*}少了$符号,正确写法是${f%%.*},否则无法正确提取文件名前缀
彻底修复后的代码
set -e # 校验入参是否为空 if [ $# -ne 1 ]; then echo "Usage: bash $0 /path/to/download/directory" exit 1 fi DOWNLOAD_DIR="$1" # 提前创建必要目录避免报错 mkdir -p "${DOWNLOAD_DIR}/mmseqs_dbs" "${DOWNLOAD_DIR}/tmp" # 直接用通配符遍历,不用ls,兼容带特殊字符的文件名 for f in "${DOWNLOAD_DIR}"/*.tar.gz; do # 跳过不存在的匹配项(避免目录下没有tar.gz文件时的报错) [ -e "$f" ] || continue # 直接使用完整路径$f,无需重复拼接前缀 tar --extract --verbose --file="$f" \ --directory="${DOWNLOAD_DIR}/mmseqs_dbs" rm "$f" # 修正变量引用错误,直接用basename提取不带后缀的文件名 BASENAME=$(basename "$f" .tar.gz) DB_NAME="${BASENAME}_db" # 用pushd/popd替代手动保存pwd,写法更简洁 pushd "${DOWNLOAD_DIR}/mmseqs_dbs" > /dev/null mmseqs tar2exprofiledb "${BASENAME}" "${DB_NAME}" mmseqs createindex "${DB_NAME}" "${DOWNLOAD_DIR}/tmp/" popd > /dev/null done
修复点说明
- 移除了不安全的
ls遍历方式,直接用shell通配符遍历文件,兼容特殊文件名 - 删除了tar命令中重复的
DOWNLOAD_DIR前缀拼接逻辑,直接使用遍历得到的完整路径 - 修正了
BASENAME提取的变量引用错误,同时用basename "$f" .tar.gz直接一步提取不带后缀的文件名,逻辑更清晰 - 增加了入参校验、必要目录预创建、无匹配文件时的跳过逻辑,鲁棒性更强
- 用
pushd/popd替代手动保存工作目录的写法,避免目录跳转错误
内容的提问来源于stack exchange,提问作者Pedro Henrique
相关产品推荐
相关产品推荐

