Chúng ta không nên quên rằng bản chất của nhiệm vụ thực sự khá đơn giản; như được đưa vào một hướng dẫn về Haskell (được viết xung quanh hoạt động thông qua giải pháp cho nhiệm vụ này, được tinh chỉnh dần dần)
Bây giờ chúng ta hãy suy nghĩ một chút về cách chương trình của chúng tôi sẽ vận hành và thể hiện nó bằng mã giả:
main = Read list of directories and their sizes.
Decide how to fit them on CD-Rs.
Print solution.
Nghe có vẻ hợp lý? Tôi cũng nghĩ vậy
Chúng ta hãy đơn giản hóa cuộc sống của mình một chút và giả sử bây giờ chúng ta sẽ tính kích thước thư mục ở đâu đó bên ngoài chương trình của chúng ta (ví dụ: với " du -sb *
") và đọc thông tin này từ stdin.
(từ hướng dẫn của Hitchhikers đến Haskell, Chương 1 )
(Bổ sung, trong câu hỏi của bạn, bạn muốn có thể điều chỉnh (chỉnh sửa) bố cục đĩa kết quả, sau đó sử dụng một công cụ để ghi chúng.)
Bạn có thể sử dụng lại (điều chỉnh và sử dụng lại) một biến thể đơn giản của chương trình từ hướng dẫn Haskell đó để chia bộ sưu tập tệp của bạn.
Thật không may, trong những distribute
công cụ mà tôi đã đề cập ở đây trong câu trả lời khác , sự đơn giản của công việc tách quan trọng là không phù hợp bởi sự phức tạp và bloatedness của giao diện người dùng của distribute
(vì nó được viết để kết hợp một số nhiệm vụ, mặc dù thực hiện theo từng giai đoạn, nhưng vẫn kết hợp không theo cách sạch nhất mà tôi có thể nghĩ đến bây giờ).
Để giúp bạn sử dụng mã của nó, đây là đoạn trích từ mã bash của distribute
(ở dòng 380 ) phục vụ cho nhiệm vụ "thiết yếu" này là chia tách bộ sưu tập tệp:
# 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() {
( đọc thêm sau dòng 454 )
Lưu ý rằng eatFiles
hàm chuẩn bị bố trí của các đĩa trong tương lai dưới dạng cây trong đó các lá là liên kết tượng trưng đến các tệp thực. Vì vậy, nó đáp ứng yêu cầu của bạn rằng bạn sẽ có thể chỉnh sửa bố cục trước khi ghi. Các mkisofs
tiện ích có một tùy chọn để làm theo liên kết tượng trưng, mà thực sự được sử dụng trong mã của tôi mkiso
chức năng .
Kịch bản được trình bày (tất nhiên là bạn có thể lấy và viết lại theo nhu cầu của mình!) Theo ý tưởng đơn giản nhất: tổng hợp kích thước của các tệp (hoặc chính xác hơn là các gói trong trường hợp distribute
) theo thứ tự chúng được liệt kê, don Không làm gì sắp xếp lại.
"Hitchhikers guide to Haskell" xem xét vấn đề tối ưu hóa nghiêm trọng hơn và đề xuất các biến thể chương trình sẽ cố gắng sắp xếp lại các tệp một cách thông minh, để chúng phù hợp hơn trên các đĩa (và yêu cầu ít đĩa hơn):
Đủ sơ bộ rồi. Hãy đi gói một số đĩa CD.
Như bạn có thể đã nhận ra, vấn đề của chúng tôi là một vấn đề cổ điển. Nó được gọi là "vấn đề về chiếc ba lô"
( google nó lên , nếu bạn chưa biết nó là gì. Có hơn 100000 liên kết).
hãy bắt đầu từ giải pháp tham lam ...
(đọc thêm trong Chương 3 và hơn thế nữa.)
Các công cụ thông minh khác
Tôi cũng được biết rằng Debian sử dụng một công cụ để tạo ra các đĩa CD phân phối thông minh hơn các distribute
bộ sưu tập gói của tôi: kết quả của nó đẹp hơn vì nó quan tâm đến các phụ thuộc giữa các gói và sẽ cố gắng tạo ra bộ sưu tập các gói. đĩa đầu tiên được đóng trong các phụ thuộc, nghĩa là không có gói nào từ đĩa thứ nhất yêu cầu gói từ đĩa khác (hoặc ít nhất, tôi muốn nói, số lượng phụ thuộc như vậy nên được giảm thiểu).