假设我有一个几 GB 的 tar 文件,但我碰巧知道写入存档的最后一个文件是我需要的重要文件。由于 tar 文件是按顺序附加的,有没有办法让 tar 从末尾读取存档以找到此文件,而不是从头开始读取超过 GB 的无关数据?
答案1
不,很遗憾没有。来自维基百科
与其他存档格式相比,tar 格式的另一个缺点是没有集中存放文件内容信息的位置(一种“目录”)。因此,要列出存档中的文件名称,必须通读整个存档并查找文件开始的位置。此外,要从存档中提取一个小文件,使用 tar 时,必须通读整个存档,查找所需文件的开始位置,而不是像其他存档格式那样在表中查找偏移量并直接转到该位置。对于大型 tar 存档,这会导致很大的性能损失,使得 tar 存档不适合经常需要随机访问单个文件的情况。
答案2
是的;如果您知道所需文件的大小,则可以使用 dd skip 复制 tar 的末尾。或者,如果您想读取整个文件一次以便以后快速随机访问,则可以使用以下命令创建索引:
tar -tRvf "$TAR"
示例脚本:
#!/bin/bash
#
# tar_extract_via_index.sh
#
TAR="$1"
RE="$2"
if [ ! -f "$TAR" ] ; then
echo "Not a file $TAR"
exit 1
fi
if [ "$RE" == "" ] ; then
echo "Expecting a $RE"
exit 2
fi
if [ ! -f "$TAR".index ] ; then
tar -tRvf "$TAR" > "$TAR".index
fi
MATCH="$(grep -P "$RE" "$TAR".index)"
if [ "$(echo "$MATCH" | grep -c .)" != "1" ] ; then
echo "Multipule matches:"
echo "$MATCH" | perl -pe 's/^/\t/g' >&2
exit 3
fi
FILE="$( echo "$MATCH" | perl -pe 's/.* \.\///g;s/.*\///g')"
SKIP="$( echo "$MATCH" | perl -pe 's/:.*//g;s/.* //g')"
COUNT="$(echo "$MATCH" | perl -pe 's/\.\/.*//g;s/.*\/[^ ]+ +//g;s/ .*//g')"
SKIP="$(echo "($SKIP+1)*512" | bc)"
dd if="$TAR" bs=1 status=none skip=$SKIP count=$COUNT of="$FILE"
echo "$FILE"
答案3
如果 tar 是在可寻址的存储上创建的,即在硬盘上而不是在磁带上,我们可以有效地查找存档中的最后一个文件。使用 GNU tar 的 -n 或 --seek 选项。(见此GNU tar 选项页面)例如,最后存储的文件名为 last_file.txt ,您可以使用以下命令
tar -nxvf <your_archive> last_file.txt
这将简单地提取 last_file.txt。由于 tar 格式在标头中包含每个文件的大小,因此可以使用 seek 系统调用有效地跳过整个文件(请参阅tar 文件格式)
为了有效地列出大型档案中的所有文件,请使用
tar -ntvf <your_archive>