Answers:
存在为此目的设计的应用程序: dirsplit
它通常生活在cdrkit
或dirsplit
包装中。
它可以创建具有链接的即用型文件夹,从而可以使用K3b或其他GUI软件轻松创建DVD。
genisoimage
软件包中找到了它。
我曾经为类似的目的制作了一个丑陋的脚本。这只是一个麻烦,但是当我写它的时候,我并不在乎执行时间或美观。我敢肯定会有更多相同概念的“产品化”版本,但是如果您希望获得一些想法或东西来开始黑客攻击,可以使用(在2008年完成,请您自担风险!):- )
#!/bin/sh -
REPO=/export/foton/PictureStore
LINKS=/export/foton/links
SPLITTIX=`date '+%y%m%d-%H%M'`
# kilobytes
DVDSIZE=4400000
PARTPREFIX="DVD-"
REPOSIZE=`du -sk -- ${REPO} | awk '{print $1}'`
NUMPARTS=`expr $REPOSIZE / $DVDSIZE`
SPLITDIR=${LINKS}/splits/${SPLITTIX}
mkdir -p -- "$SPLITDIR"
PARTNUM=1
PARTSIZ=0
DONESIZ=0
PARTNUM=`echo $PARTNUM | awk '{printf("%03x", $0)}'`
mkdir -p -- "${SPLITDIR}/${PARTPREFIX}${PARTNUM}"
for D in "${REPO}"/..?* "${REPO}"/.[!.]* "${REPO}"/*
do
if [ ! -e "$D" ]; then continue; fi # skip ..?*, .[!.]* and * if there are no matching files
D=${D#$REPO/}
D_SIZ=`du -sk -- "${REPO}/$D" | awk '{print $1}'`
if test `expr $D_SIZ + $PARTSIZ` -le $DVDSIZE
then
# link to D in this part
ln -s -- "$REPO/$D" "${SPLITDIR}/${PARTPREFIX}${PARTNUM}/$D"
# adjust counters
PARTSIZ=`expr $PARTSIZ + $D_SIZ`
DONESIZ=`expr $DONESIZ + $D_SIZ`
else
# next part and link to D in that
echo PART $PARTNUM: $PARTSIZ kb '(target' $DVDSIZE 'kb)'
PARTNUM=`expr $PARTNUM + 1`
PARTNUM=`echo $PARTNUM | awk '{printf("%03x", $0)}'`
PARTSIZ=$D_SIZ
DONESIZ=`expr $DONESIZ + $D_SIZ`
mkdir -p -- "${SPLITDIR}/${PARTPREFIX}${PARTNUM}"
ln -s -- "$REPO/$D" "${SPLITDIR}/${PARTPREFIX}${PARTNUM}/$D"
fi
done
echo "wrote $DONESIZ kb in $PARTNUM parts in $SPLITDIR"
我想我已经通过samba将结果共享给了从其中刻录光盘的Windows主机。如果您使用以上未更改的内容,则可能希望使用mkisofs
或其他可解决符号链接的存档器。
\[?*
)。建议阅读:不要解析ls,$ VAR vs $ {VAR} 的输出,并且不要引用或引用。请注意,我尚未测试生成的脚本。如果您不了解我的更改,请随时提出。
[
相反的test
我曾经写过一个脚本来解决类似的问题-我称它为“分发”(您可以阅读脚本的主要代码或带有帮助消息的文件,也可以将其打包下载);从其描述:
分发 -将软件包集合分发到多张CD上(特别适合将来与APT一起使用)
描述:`distribute'程序使完成与创建CD集以分发软件包集合有关的任务更加容易。任务包括:布置CD文件系统(将大量软件包拆分为几张光盘等),准备要由APT使用的集合(索引),创建ISO映像并记录光盘。
可以在“ distribute”的帮助下发布对最初分发的集合的定期更新。
它分几个阶段完成整个过程:在一个阶段,它使用到原始文件的符号链接创建粗盘“布局”,因此您可以进行干预并更改未来的磁盘树。
可以在脚本打印的帮助消息中(或通过查看源代码)阅读有关其用法的详细信息。
编写此文件时会考虑到更棘手的用例(将更新作为“ diff”(添加的新文件集)发布到原始记录的文件集合中),因此它包括一个额外的初始阶段,即“修复“文件集合的当前状态(为简单起见,它是通过符号链接复制原始文件集合的方式,在一个特殊的工作位置保存该集合的状态;然后,在将来的某个时间,将能够在文件集合的将来当前状态和此保存状态之间创建差异。因此,尽管您可能不需要此功能,但是您不能跳过此初始阶段AFAIR。
另外,我现在不确定(我是在几年前写的)它是否能很好地处理复杂的树,还是应该仅分割简单(一级)文件目录。(请务必查看帮助消息或源代码;稍后,我将在一段时间后再进行查找。)
与APT有关的内容是可选的,因此请不要注意,如果不需要,它可以准备供APT使用的软件包集合。
当然,如果您有兴趣,可以随时根据需要重写或提出改进建议。
(请注意,该软件包还包含未在上面链接的Git存储库中显示的代码清单中应用的其他有用的补丁!)
distribute
该摘录解决了此处所要求的基本任务。
我们不应忘记任务的实质确实很简单;如关于Haskell的教程中所写(围绕该任务的解决方案的实现而编写,逐步完善)
现在让我们考虑一下我们的程序将如何运行并以伪代码表示它:
main = Read list of directories and their sizes. Decide how to fit them on CD-Rs. Print solution.
听起来合理吗?我是这么想的。
让我们简化一下生活,现在假设我们将在程序之外的某个地方计算目录大小(例如,使用“
du -sb *
”),并从stdin中读取此信息。
(摘自《搭便车指南》《 Haskell》第1章)
(此外,在您的问题中,您希望能够调整(编辑)生成的磁盘布局,然后使用工具来刻录它们。)
您可以重用(适应和重用)该Haskell教程中程序的一个简单变体,以拆分文件集合。
不幸的是,在我在另一个答案中提到的distribute
工具中,基本拆分任务的简单性与的用户界面的复杂性和膨胀性不匹配distribute
(因为它被编写为组合多个任务;尽管分阶段执行,但仍然无法以我现在能想到的最干净的方式结合在一起)。
为了帮助您更好地利用其代码,以下是bash代码的摘录distribute
(在380行),该摘录用于完成拆分文件集合的“基本”任务:
# Splitting:
function splitMirrorDir() {
if [[ ! -d "$THIS_BASES_DIR/$BASE/$type" ]]; then
echo $"No base fixed for $type" >&2
exit 1
fi
# Getting the list of all suitable files:
local -a allFiles
let 'no = 0' ||:
allFiles=()
# no points to the next free position in allFiles
# allFiles contains the constructed list
for p in "$THIS_BASES_DIR/$BASE/$type"/*.rpm; do
if [[ ! -e "$p" ]]; then
# fail on non-existent files
echo $"Package file doesn't exist: " "$p" >&2
return 1
fi
if [[ "$ONLY_REAL_FILES" == "yes" && ! -f "$p" ]]; then
continue
fi
if [[ "$DIFF_TO_BASE" ]]; then
older_copy="$DIFF_TO_BASE/$type/${p##*/}" # using shell param expansion instead of `basename' to speed up
if [[ -h "$older_copy" || -a "$older_copy" ]]; then
continue
fi
fi
allFiles[$(( no++ ))]="$p"
done
readonly -a allFiles
# Splitting the list of all files into future disks:
#
local -a filesToEat allSizes
let 'no = 0' ||:
filesToEat=()
allSizes=($(getSize "${allFiles[@]}"))
readonly -a allSizes
# allSizes contains the sizes corrsponding to allFiles
# filesToEat hold the constructed list of files to put on the current disk
# no points to the next free position in filesToEat
# totalSize should hold the sum of the sizes
# of the files already put into filesToEat;
# it is set and reset externally.
for p in "${allFiles[@]}"; do
if (( totalsize + ${allSizes[$(( no ))]} > CDVOLUME )); then
eatFiles "${filesToEat[@]}"
filesToEat=()
finishCD
startTypedCD
fi
let "totalsize += ${allSizes[$(( no ))]}" ||:
filesToEat[$(( no++ ))]="$p"
done
eatFiles "${filesToEat[@]}"
}
function eatFiles() {
#{ oldIFS="$IFS"; IFS=$'\n'; echo "$FUNCNAME: args: " "$*" | head >&2; IFS="$oldIFS"; }
zeroDelimited "$@" | xargs -0 --no-run-if-empty \
cp -s \
--target-dir="$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"/ \
--
}
function startTypedCD() {
# set -x
mkdir -p "$THIS_LAYOUTS_DIR/cd$(( cdN ))/$PREFIX/$type$DOT_SUFFIX"
start_action $" %s with %s" "$(( cdN ))" "$type"
# set +x
}
function finishCD() {
请注意,该eatFiles
函数将未来磁盘的布局准备为树,其中叶子是指向实际文件的符号链接。因此,满足您的要求,即您应该能够在刻录之前编辑布局。该mkisofs
实用程序具有遵循符号链接的选项,该符号链接实际上已在我的mkiso
函数的代码中使用。
呈现的脚本(当然,您可以根据需要重写并重写!)遵循最简单的想法:distribute
按照列出的顺序对文件(或更确切地说,对于包)的大小求和,不做任何重新排列。
“ Haskell旅行者指南”更加认真地考虑了优化问题,并提出了程序变体,这些变体将尝试智能地重新排列文件,以使它们更好地适合磁盘(并且需要更少的磁盘):
预赛已经足够了。让我们打包一些CD。
您可能已经意识到,我们的问题是经典的。这被称为“背包问题” (如果您还不知道它是什么,可以用谷歌搜索一下。有超过100000个链接)。
让我们从贪婪的解决方案开始...
(在第3章中有更多了解,并继续。)
有人还告诉我Debian使用一种工具来制作发行CD,比我的distribute
wrt软件包集合更智能:其结果更好,因为它关心软件包间的依赖关系,并会尝试使软件包的集合得以继续。在依赖关系下关闭的第一个磁盘,即,第一个磁盘上的任何软件包都不应要求另一个磁盘上的软件包(或者至少,我要说这样的依赖关系的数量应最小化)。
该rar
归档可以指示自动分割它创建了与特定大小的块存档-vsize
标志。
将该目录树归档为foo
您指定的每个块(例如每个块500 MB)
rar a backup.rar -v500m foo/
rar
,除非您再次将每个“零件”解压缩到其自己的目录中,这当然是行不通的,因为零件不是那样设计的,并且不会在文件边界上拆分。
tar
+ split
结果的工具,那么还有dar ; 这是有关其相关功能的注释:“(SLICES)设计为能够将归档分割成多个可移动介质,而无论其数量和大小如何。” 我认为,与tar
+ 相比split
,它提供了一些更简便的方法来访问存档文件。(顺便说一句,它也具有类似的功能distribute
:“差异备份”和“目录树快照”,但是可能不喜欢结果是一种特殊格式,而不是带有目录树的ISO。)