问题现象描述
在使用wget从sourceforge等网站下载压缩包时,经常会遇到文件名包含URL参数的情况,例如:
SQliteManager-1.2.4.tar.gz?r=http:%2F%2Fsourceforge.net%2Fprojects%2Fsqlitemanager%2Ffiles%2F&ts=1305711521&use_mirror=switch
直接使用tar命令解压时会报错:
tar (child): Cannot connect to SQliteManager-1.2.4.tar.gz?r=http: resolve failed
gzip: stdin: unexpected end of file
tar: Child returned status 128
tar: Error is not recoverable: exiting now
问题根源分析
这个问题主要由两个因素导致:
- 文件名中包含特殊字符(?、=、&等),这些字符在shell中有特殊含义
- tar命令会将文件名中的部分内容错误解析为参数或URL
实用解决方案
这里提供几种实用的解决方法,适用于不同场景:
方法1:使用引号包裹文件名
最简单的方式是用单引号或双引号包裹整个文件名:
tar xzf "SQliteManager-1.2.4.tar.gz?r=http:%2F%2Fsourceforge.net%2Fprojects%2Fsqlitemanager%2Ffiles%2F&ts=1305711521&use_mirror=switch"
方法2:使用反斜杠转义特殊字符
对每个特殊字符进行转义处理:
tar xzf SQliteManager-1.2.4.tar.gz\?r\=http\:%2F%2Fsourceforge.net%2Fprojects%2Fsqlitemanager%2Ffiles%2F\&ts\=1305711521\&use_mirror\=switch
方法3:使用wget时指定输出文件名
下载时就指定干净的文件名:
wget "http://sourceforge.net/projects/sqlitemanager/files/SQliteManager-1.2.4.tar.gz" -O SQliteManager-1.2.4.tar.gz
方法4:使用管道解压
完全避免文件名问题:
cat "SQliteManager-1.2.4.tar.gz?r=http:%2F%2Fsourceforge.net%2Fprojects%2Fsqlitemanager%2Ffiles%2F&ts=1305711521&use_mirror=switch" | tar xz
自动化处理脚本
对于经常需要处理这类问题的用户,可以创建以下bash脚本:
#!/bin/bash
for file in *.tar.gz*; do
newname=$(echo "$file" | awk -F'?' '{print $1}')
if [ "$file" != "$newname" ]; then
mv -v "$file" "$newname"
tar xzf "$newname"
fi
done
注意事项
- 使用引号方法时,确保引号匹配正确
- 转义字符方法容易出错,建议优先使用引号
- 管道方法会丢失原始文件名信息
- 自动化脚本需要测试后再用于生产环境