Nie powinniśmy zapominać, że istota zadania jest rzeczywiście dość prosta; jak w tutorialu o Haskell (który jest napisany na temat pracy nad rozwiązaniem dla tego zadania, stopniowo udoskonalany)
Zastanówmy się teraz przez chwilę, jak nasz program będzie działał, i wyrażmy to w pseudokodzie:
main = Read list of directories and their sizes.
Decide how to fit them on CD-Rs.
Print solution.
Brzmi rozsądnie? Tak myślałem.
Uprośćmy trochę nasze życie i załóżmy na razie, że obliczymy rozmiary katalogów gdzieś poza naszym programem (na przykład za pomocą „ du -sb *
”) i odczytamy te informacje ze standardowego wejścia.
(z przewodnika Autostopowiczów po Haskell, rozdział 1 )
(Dodatkowo w swoim pytaniu chciałbyś mieć możliwość dostosowania (edycji) powstałych układów dysków, a następnie skorzystania z narzędzia do ich wypalenia).
Możesz ponownie użyć (dostosować i ponownie użyć) prostego wariantu programu z tego samouczka Haskell do dzielenia kolekcji plików.
Niestety, w tym distribute
narzędzia, które już wspomniano tu w innej odpowiedzi , prostota zasadniczego zadania łupania nie towarzyszy złożoności i bloatedness w interfejsie użytkownika distribute
(ponieważ został napisany aby połączyć kilka zadań, chociaż wykonywane etapami, ale nadal łączy się nie w najczystszy sposób, jaki mógłbym teraz wymyślić).
Aby pomóc ci w pewnym stopniu wykorzystać jego kod, oto fragment kodu bash distribute
(w linii 380 ), który służy do wykonania tego „niezbędnego” zadania dzielenia kolekcji plików:
# 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() {
( czytaj więcej po linii 454 )
Zauważ, że eatFiles
funkcja przygotowuje układy przyszłych dysków jako drzewa, w których liście są dowiązaniami symbolicznymi do rzeczywistych plików. Tak więc spełnia twoje wymagania, abyś mógł edytować układy przed nagraniem. mkisofs
Narzędzie ma możliwość śledzić dowiązania symboliczne, które rzeczywiście jest stosowany w kodzie mojej mkiso
funkcji .
Prezentowany skrypt (który możesz oczywiście zabrać i przepisać zgodnie z własnymi potrzebami!) Podąża za najprostszym pomysłem: zsumować rozmiary plików (a dokładniej w przypadku pakietów distribute
) dokładnie w kolejności, w jakiej zostały wymienione. nie rób żadnych zmian.
„Przewodnik autostopowiczów po Haskell” poważniej traktuje problem optymalizacji i sugeruje warianty programów, które próbowałyby inteligentnie zmienić rozmieszczenie plików, aby lepiej pasowały do dysków (i wymagały mniejszej liczby dysków):
Już wystarczająco dużo wstępnych kwalifikacji. chodźmy spakować trochę płyt CD.
Jak już zapewne zauważyliście, nasz problem jest klasyczny. Nazywa się to „problemem plecakowym”
( google go w górę , jeśli jeszcze nie wiesz, co to jest. Istnieje ponad 100000 linków).
zacznijmy od chciwego rozwiązania ...
(czytaj więcej w rozdziale 3 i dalszych.)
Inne inteligentne narzędzia
Powiedziano mi również, że Debian korzysta z narzędzia, które sprawia, że jego dyski CD są mądrzejsze niż moje distribute
kolekcje wrt pakietów: jego wyniki są ładniejsze, ponieważ dba o zależności między pakietami i próbowałby stworzyć kolekcję pakietów, która działa na pierwszy dysk jest zamknięty w zależnościach, tzn. żaden pakiet z pierwszego dysku nie powinien wymagać pakietu z innego dysku (lub, przynajmniej powiedziałbym, liczbę takich zależności należy zminimalizować).