Witam, odgrzeję trochę temat...
znalazłem w necie skrypt do backup'u różnicowego danych autorstwa:
Robert "LiNiO" Litwiniec #
[email protected] http://linio.net2000.pl
i właśnie go testuję. Oto on w oryginale:
Kod: Zaznacz cały
Skrypt do wykonywania kopii bezpieczeństwa (na licencji GNU GPL):
#!/bin/bash
###################################################################
# #
# Skrypt do wykonywania kopii bezpieczeństwa plików i katalogów #
# Korzysta z pliku konfiguracyjnego, w którym mogą być podane #
# nazwy narzędzi wykorzystywanych do archiwizacji, kompresji, #
# odpowiednie opcje wywołań tych programów. #
# Plik konfiguracyjny zawiera informacje o katalogach i sposobach #
# ich archiwizacji (pełna lub różnicowa od ostatniej kopii #
# pełnej). #
# #
# Skrypt posiada większość predefiniowanych opcji, których #
# wartości mogą być zmieniane w pliku konfiguracyjnym. #
# Z linii poleceń można wymusić wykonanie pełnej kopii #
# niezależnie od ustawień w pliku konfiguracyjym, wymusić #
# archiwizację bez kompresji (np. gdy zależy nam na czasie). #
# Można również wymisuć korzystanie z podanego z linii komend #
# pliku konfiguracyjnego #
# #
# Program obsługuje archiwizację programami tar i cpio #
# Kompresja jest możliwa przy użyciu programów bzip2, gzip #
# oraz compress #
# Sprawdzana jest ilość wolnego miejsca na partycji z katalogiem #
# do którego będą zapisywane pliki archiwum. #
# W przypadku dysków podmontownaych przy pomocy NFS sprawdzana #
# jest dostępność zasobów danego serwera #
# Jednocześnie może działać kilka sesji skryptu #
# Usuwanie identycznych kopii różnicowych (poprzez porównanie #
# dwóch kolejnych kopii - jeśli są identyczne ostatnia jest #
# usuwana. #
# #
# Lista życzeń: #
# Istnieje możliwość podania alternatywnego katalogu na pliki #
# z archiwum - wykorzystanego w przypadku np. niedziałania NFS #
# lub przy możliwości przepełnienia katalogu pierwotnego #
# #
# Podczas archiwizacji przygotowanie pliku z opisem archiwum #
# #
# Przygotowanie obrazów ISO płyt CD z archiwum, ewentualne #
# formatowanie płyty CD-RW oraz wypalenie takiej płyty #
# #
# opcja -t --test - testowanie działania programu np. na innych #
# platformach #
# #
# Przy braku miejsca warunkowe wykonanie kopii przy włączonej #
# kompresji - uruchomienie dodatkowego procesu sprawdzającego #
# wolne miejsce w systemie plików i ewentualnie zabijającego #
# proces archiwizujący ten katalog #
# #
# #
# Ograniczenia: #
# Kłopoty z plikami zawierającymi spacje - możliwe rozwiązanie #
# powinno obejmować sprawdzenie czy dana wersja narzędzi (find, #
# tar, cpio) obsługuje opcję -print0 (narzędzia GNU tak). #
# #
# #
# Parametry, które mogą zostać przekazane do skryptu #
# #
# kopia [[-c config_file] [-f] [-nc] | -h | -V] #
# #
# -c config, --config config - podany plik konfiguracyjny #
# -f, --force-full - pełna kopia #
# -nc, --no-compression - bez kompresji #
# -h, --help - pomoc #
# -V, --version - wersja #
# #
# #
# Przetestowane na: #
# SunOS 5.6 SUN4U Sparc Ultra-250, 128MB RAM, 2x9GB HDD #
# Linux 2.2.18 Debian GNU/Linux Celeron 333, 192MB RAM, 105GB HDD #
# Linux 2.2.18 Debian GNU/Linux Celeron 416, 128MB RAM, 21GB HDD #
# #
# Robert "LiNiO" Litwiniec #
# [email][email protected][/email] [url]http://linio.net2000.pl[/url] #
# Zamość, 2001.01.22 #
# #
###################################################################
WERSJA=0.78
###################################################################
# #
# Zmienne, które można bezproblemowo modyfikować #
# #
# NAZWA #
# #
###################################################################
###################################################################
# #
# Definicje kodów powrotu zwracanych przez program #
# #
###################################################################
OK=0
NO_CONFIG_FILE=5
EMPTY_CONFIG_FILE=6
CANT_MAKE_TEMP_DIR=7
FILE_IS_A_LINK=8
NO_DEST_DIR_SPECIFIED=9
CANT_MAKE_DEST_DIR=10
NO_ARCHIVIZER=11
NO_PACKER=12
CANT_CHANGE_TO_ROOT_DIR=13
HOST_IS_DEAD=14
THAT_CANT_HAPPEN=15
###################################################################
# #
# Funkcja sprawdza czy w pliku KONFIGURACJA znajduje się linia #
# rozpoczynająca się ciągiem znaków PARAM= #
# Jeżeli znajdzie taką linię, zmiennej VALUE nadaje wartość #
# przypisaną do tego parametru. #
# Jeżeli nie znajdzie, zwraca kod powrotu 1 #
# #
# Wyjście : - #
# Korzysta z: PARAM, KONFIGURACJA, VALUE #
# Modyfikuje: PARAM (warunkowo), VALUE #
# Kod powrotu: 0 - gdy znalazł odpowiedni parametr #
# 1 - gdy nie znalazł parametru #
# #
###################################################################
function get_param(){
VALUE=`grep "^$PARAM=" $KONFIGURACJA|awk -F'=' '{print $2}'`
[ -z "$VALUE" ] && \
return 1
export $PARAM=$VALUE
return 0
}
###################################################################
# #
# Funkcja sprawdza czy plik PLIK dowiązaniem twardym (do i-węzła) #
# lub symbolicznym # #
# #
# Wyjście : - #
# Korzysta z : PLIK #
# Modyfikuje : - #
# Kod powrotu : 0 - gdy PLIK jest dowiązaniem do innego pliku #
# 1 - gdy nie jest dowiązaniem #
# #
###################################################################
function test_link(){
[ $(ls -l $PLIK 2>/dev/null|awk '{print $2}') -gt 1 \
-o -n "$(ls -l $PLIK 2>/dev/null|grep ^l )" ] \
|| return 0
return 1
}
###################################################################
# #
# Funkcja wypisuje nazwę programu i dostępne parametry # #
# #
# Wyjście : nazwa programu i parametry #
# Korzysta z : nazwa pliku #
# Modyfikuje : - #
# #
###################################################################
function usage(){
echo "$0: [[-c config_file] [-f] [-nc] | -h | -V ]"
}
###################################################################
# #
# Funkcja wypisuje nazwę programu i jego wersję # #
# #
# Wyjście : nazwa programu i wersja #
# Korzysta z: WERSJA #
# #
# Modyfikuje: - #
# #
###################################################################
function version(){
echo "$(basename $0) wersja $WERSJA"
}
###################################################################
# #
# Ze ścieżki dostępu do pliku (zmienna NAZWA) wyrzuca pierwszy #
# znak, jeśli znakiem tym jest '/'. #
# #
# Wyjście : ścieżka dostępu bez znaku '/' na początku #
# Korzysta z: NAZWA #
# Modyfikuje: - #
# #
###################################################################
function remove_trailing_slash(){
#sprawdzamy czy nazwa katalogu zaczyna sie od "/"
echo $NAZWA|grep >/dev/null '^/'
if [ $? -eq 0 ]
then
#jezeli jest tam "/" to go usuniemy....
echo $NAZWA|cut -c2-
else
echo $NAZWA
fi
}
###################################################################
# #
# Wykonujemy zamianę znaków '/' na '_', aby można było nazwę #
# katalogu przedstawić jako składnik nazwy archiwum #
# #
# Wyjście : zamienia znaki '/' na '_' #
# Korzysta z: NAZWA #
# Modyfikuje: - #
# #
###################################################################
function slash2underscore(){
echo $NAZWA|tr '/' '_'
}
###################################################################
# #
# Tworzy dwie zmienne przechowujące nazwę pliku i jego rozmiar #
# Zostanie to wykorzystane do porównania archiwów z dwóch #
# kolejnych wywołań kopii. #
# #
# Wyjście : - #
# Korzysta z: #
# Modyfikuje: POPRZEDNI_ROZMIAR, POPRZEDNI_PLIK #
# #
###################################################################
function poprzedni_plik(){
POPRZEDNI_ROZMIAR=$(ls -ltk 2>/dev/null $DEST_DIR/$PRZEDROSTEK*$(slash2underscore)."$ARCHIWIZER""$KOMPRESJA_PRZYROSTEK" \
| head -1 \
| awk '{print $5}')
[ ! -z "$POPRZEDNI_ROZMIAR" ] &&
POPRZEDNI_NAZWA=$(ls -ltk $DEST_DIR/$PRZEDROSTEK*$(slash2underscore)."$ARCHIWIZER""$KOMPRESJA_PRZYROSTEK" \
| head -1 \
| awk '{print $9}')
}
###################################################################
# #
# Tworzy nazwę pliku poprzez połączenie odpowiednich zmiennych #
# #
# Wyjście : nazwa pliku #
# Korzysta z: PRZEDROSTEK, DATA_FMT, NAZWA #
# ARCHIWIZER, KOMPRESJA_PRZYROSTEK #
# Modyfikuje: - #
# #
###################################################################
function nazwa_pliku(){
echo $PRZEDROSTEK$(date +$DATA_FMT)$(slash2underscore)."$ARCHIWIZER""$KOMPRESJA_PRZYROSTEK"
}
###################################################################
# #
# Sprawdza ilość bloków zajmowanych przez plik lub katalog #
# o nazwie NAZWA #
# #
# Wyjście : rozmiar pliku katalogu w blokach #
# Korzysta z: NAZWA #
# Modyfikuje: - #
# #
###################################################################
function rozmiar(){
echo $(du -sk $NAZWA|cut -f1);
}
###################################################################
# #
# Sprawdza wolne miejsce na partycji, na której znajduje się #
# katalog NAZWA #
# #
# Wyjście : liczba bloków #
# Korzysta z: NAZWA #
# Modyfikuje: - #
# #
###################################################################
function wolne_miejsce(){
df -k $NAZWA\
| tail -1 \
| awk ' {
print $4
}'
}
###################################################################
# #
# Sprawdza czy katalog o nazwie NAZWA jest montowany poprzez NFS #
# katalog NAZWA #
# #
# Wyjście : nazwa hosta/IP #
# Korzysta z: NAZWA #
# Modyfikuje: - #
# Kod powrotu: 0 jeżeli katalog NAZWA jest montowany poprzez NFS #
# 1 jeżeli nie jest #
# #
###################################################################
function dir_nfs(){
echo $(df -k $NAZWA\
| tail -1 \
| awk ' {print substr($1,0,index($1,":")-1)}')
}
###################################################################
# #
# Usuwanie plików tymczasowych #
# #
###################################################################
function posprzataj(){
[ "$DEBUG" = "1" ] && \
echo "usuwam pliki tymczasowe"
rm -f "$TEMP"/kopia{.lista,.conf,0,1} #2>/dev/null
rmdir "$TEMP"
}
###################################################################
# #
# Funkcja sprawdza czy maszyna o nazwie/IP NAZWA odpowiada #
# na pingi. #
# #
# Wyjście : - #
# Korzysta z: NAZWA #
# #
# Modyfikuje: - #
# Kod powrotu: 0 - maszyna żyje #
# 1 - brak odpowiedzi #
# #
###################################################################
function pinguj(){
# jeżeli jest to maszyna z systemem linux
# wysyłamy 3 pingi i jeśli przejdą zwracamy kod 0
echo $MACHTYPE \
| grep linux >/dev/null && \
ping -c3 $NAZWA >/dev/null &&
return $OK
echo $MACHTYPE \
| grep sun >/dev/null
if [ $? -eq 0 ]
then
# jeśli mamy pinga w ścieżce poszukiwań
type ping 2>/dev/null >/dev/null
if [ $? -eq 0 ]
then
ping $NAZWA 3 >/dev/null&&
return $OK
else
# jeśli nie, to podajemy ścieżkę do pinga
# (sprawdzane na SunOS5.6 Sparc Solaris)
/usr/sbin/ping $NAZWA 3 >/dev/null&&
return $OK
fi
fi
return 1
}
###################################################################
# #
# Funkcja sprawdza czy pliki istnieją, czy nie są linkami #
# symbolicznymi albo twardymi itp. #
# #
# Wyjście : - #
# Korzysta z: TEMP, DEBUG, VERBOSE #
# #
# Modyfikuje: PLIK #
# #
###################################################################
function kopia_link(){
for PLIK in $TEMP/kopia.conf $TEMP/kopia1 $TEMP/kopia0
do
[ "$DEBUG" = "1" ] && \
echo "sprawdzam istnienie pliku $PLIK"
#sprawdzamy czy istnieje plik, do którego będziemy chcieli coś zapisywać
if [ -f $PLIK ]
then
echo "Plik $PLIK już istnieje"
[ "$DEBUG" = "1" ] && \
echo "sprawdzam czy plik $PLIK jest linkiem"
test_link
if [ $? -gt 0 ]
then
echo "- Plik $PLIK już istnieje i jest on linkiem do innego pliku!";
echo "- Przerywam działanie programu";
exit "$FILE_IS_A_LINK";
fi
fi
#zerujemy plik
>$PLIK
done
}
#Definicje ścieżek dostępu do plików konfiguracyjnych
unset KONFIGURACJA
KONF1="/etc/kopia/kopia.conf"
KONF2="$HOME/etc/kopia/kopia.conf"
#KONF3="$HOME/.etc/kopia.conf"
KONF3="/kopia2/kopia.conf"
# sprawdzamy istnienie plików konfiguracyjnych
# Waga plików wzrasta wraz z kolejnością
[ -f "$KONF1" ] && KONFIGURACJA=$KONF1
[ -f "$KONF2" ] && KONFIGURACJA=$KONF2
[ -f "$KONF3" ] && KONFIGURACJA=$KONF3
# parametry muszą być (o ile istnieją) przekazane wg. wzorca:
# [[-c nazwa] [-f] [-nc]] | [-h] | [-V]
# lub wg. dłuższego zapisu:
# [[--config-file nazwa] [--force-full] [--no-compression]]
# | [--help] | [--version]
#jeśli do skryptu przekazano jakieś parametry
if [ $# -gt 0 ]
then
# wykorzystanie podanego pliku konfiguracyjnego
[ "$1" == "-c" -o "$1" == "--config" ] && \
{ KONFIGURACJA="$2" ; shift 2; }
# wymuszenie pełnej kopii wszystkich katalogów
[ "$1" == "-f" -o "$1" == "--force-full" ] && \
FULL=true
# wymuszenie archiwizacji bez kompresji
[ "$1" == "-nc" -o "$1" == "--no-compression" ] && \
PACKER=false
# krótki opis programu
[ "$1" == "-h" -o "$1" == "--help" ] && \
{ usage ; exit $OK; }
# wersja programu
[ "$1" == "-V" -o "$1" == "--version" ] && \
{ version ; exit $OK; }
fi
# sprawdzamy czy zmienna KONFIGURACJA ma nadaną wartość
[ -z "$KONFIGURACJA" ] && \
{ echo "- Nie mogę odnaleźć plików konfiguracyjnych"; \
exit "$NO_CONFIG_FILE"; }
# czy plik KONFIGURACJA jest pusty
[ ! -s "$KONFIGURACJA" ] && \
{ echo "- Plik konfiguracyjny $KONFIGURACJA jest pusty!!!";\
exit "$EMPTY_CONFIG_FILE"; }
DEBUG="0"
PARAM=DEBUG
get_param
VERBOSE="0"
PARAM=VERBOSE
get_param
TEMP="/tmp"
PARAM=TEMP
get_param
UMASK="077"
PARAM=UMASK
get_param
# Jeśli został podany z linii komend parametr -nc (--no-compression)
# to nie jest pobierany parametr $PACKER z pliku konfiguracyjnego
if [ -z "$PACKER" ]
then
PACKER="bzip2"
PARAM=PACKER
get_param
else
unset PACKER
fi
PARAM=DEST_DIR
get_param
DATA_FMT="%y%m%d_%H%M"
PARAM=DATA_FMT
get_param
PARAM=POPRZEDNI_USUWAJ
get_param
PRZEDROSTEK_DZIEN="dzien";
PRZEDROSTEK_FULL="full";
ARCHIWIZER="cpio"
PARAM=ARCHIWIZER
get_param
case "$ARCHIWIZER" in
tar)
ARCHIWIZER_OPCJE="-cf"
;;
cpio)
ARCHIWIZER_OPCJE="-o -a -H crc"
;;
esac
PARAM=ARCHIWIZER_OPCJE
get_param
# przy tworzeniu archiwum będą wypisywane informacje o plikach na stderr
ARCHIWIZER_VERBOSE=" -v"
# pobieramy numer dnia miesiąca
DZIEN=$(date '+%d')
# sprawdzamy do jakiego katalogu będziemy zapisywali pliki archiwum
[ "$DEBUG" = "1" ] && \
echo "sprawdzamy DEST_DIR=$DEST_DIR"
# Jeżeli w pliku konfiguracyjnym nie ma linii definiującej katalog DEST_DIR
# kończymy działanie skryptu
if [ -z "$DEST_DIR" ]
then
echo "- Nie mogę odnaleźć w pliku konfiguracyjnym $KONFIGURACJA linii DEST_DIR="
exit "$NO_DEST_DIR_SPECIFIED"
fi
# Jeżeli brakuje katalogu DEST_DIR
if [ ! -d "$DEST_DIR" ]
then
[ "$VERBOSE" = "1" ] && echo "- Nie mogę odnaleźć katalogu $DEST_DIR. Próbuję go utworzyć"
mkdir $DEST_DIR
if [ $? -eq 0 ]
then
[ "$VERBOSE" = "1" ] && \
echo "Utworzyłem katalog $DEST_DIR"
else
echo "- Próba utworzenia katalogu $DEST_DIR nie powiodła się - koniec działania skryptu"
exit "$CANT_MAKE_DEST_DIR"
fi
fi
[ "$DEBUG" = "1" ] && \
echo "zmienna DEST_DIR=$DEST_DIR"
# jeżeli nie istnieje katalog dla plików tymczasowych
if [ ! -d "$TEMP" ]
then
[ "$VERBOSE" = "1" ] && \
echo "* Nie istnieje katalog $TEMP. Próbuję go utworzyć."
# tworzenie katalogu
mkdir "$TEMP"
# czy udała się próba utworzenia katalogu?
if [ $? -gt 0 ]
then
echo "- Nie mogę utworzyć katalogu $TEMP. Wyjście z programu"
exit "$CANT_MAKE_TEMP_DIR"
fi
fi
# Teraz zrobimy coś, co pozwoli na jednoczesne działanie kilku kopii
# - tworzymy w katalogu TEMP podkatalog kopia_PID - gdzie PID
# to numer procesu
# tworzenie katalogu
mkdir "$TEMP/kopia$$"
# czy udała się próba utworzenia katalogu?
if [ $? -gt 0 ]
then
echo "- Nie mogę utworzyć katalogu $TEMP/kopia$$. Wyjście z programu"
exit "$CANT_MAKE_TEMP_DIR"
fi
TEMP="$TEMP/kopia$$"
#wypisujemy aktualną datę
#[ "$VERBOSE" = "1" ] && \
date
[ "$VERBOSE" = "1" ] && \
echo -e "Konfiguracja z pliku $KONFIGURACJA\n"
#ustawiamy maskę dla nowo tworzonych plików
[ "$DEBUG" = "1" ] && \
echo "ustawiam maskę dla plików tymczasowych w katalogu $TEMP na $UMASK"
umask $UMASK
# sprawdzanie plików, które będą tworzone w katalogu TEMP, czy nie są linkami
# (symbolicznymi lub twardymi)
kopia_link
[ "$DEBUG" = "1" ] && \
echo "usuwam komentarze"
#usuwamy komentarze (linie rozpoczynające się od znaku '#') z pliku konfiguracyjnego
grep -v '^#' $KONFIGURACJA >$TEMP/kopia.conf
#czy podczas działania programu do kompresji dane mają być przepuszczane
#przez filtr/kompresor
[ "$DEBUG" = "1" ] && \
echo "kompresor danych=$PACKER"
#definicje rozszerzeń nazw plików dla poszczególnych kompresorów
# czy jest zdefiniowany program do kompresji
if [ ! -z "$PACKER" ]
then
# Sprawdzamy czy program do kompresji znajduje się w aktualnej
# ścieżce poszukiwań
type "$PACKER" >/dev/null 2>/dev/null
# jeżeli polecenie type (wbudowane w bash) znalazło coś
# lub istnieje plik wykonywalny (zadziała gdy podamy pełną
# ścieżkę do programu kompresujacego)
if [ $? -eq 0 -o -x "$PACKER" ]
then
case `basename $PACKER` in
bzip2)
KOMPRESJA_PRZYROSTEK=".bz2"
;;
gzip)
KOMPRESJA_PRZYROSTEK=".gz"
;;
compress)
KOMPRESJA_PRZYROSTEK=".Z"
;;
esac
else
echo "Brak programu do kompresji $PACKER - dane nie będą kompresowane"
unset PACKER
fi
fi
[ "$DEBUG" = "1" ] && \
echo -e "kompresja przyrostek=$KOMPRESJA_PRZYROSTEK\n\n"
#przepisywanie do odpowiednich plików informacji o tym, czy kopia ma być pełna (0)
#czy różnicowa (1)
awk "{
if (\$1 == 1)
print \$2 >\"$TEMP\"\"/kopia1\"
}" $TEMP/kopia.conf
awk "{
if (\$1 == 0)
print \$2 >\"$TEMP\"\"/kopia0\"
}" $TEMP/kopia.conf
#przechodzimy do katalogu nadrzędnego - "/"
cd / || \
exit "$CANT_CHANGE_TO_ROOT_DIR"
# sprawdzamy czy jest to pierwszy dzień miesiąca (wykonujemy wówczas kopię pełną)
# lub ustawiona jest flaga FULL - wykonujemy kopię pełną, nawet w przypadku
# plików, które zostały oznaczone do kopii różnicowej
if [ $[DZIEN] -eq "1" -o -n "$FULL" ]
then
cat $TEMP/kopia1 >>$TEMP/kopia0
#zerujemy plik z kopią różnicową
>$TEMP/kopia1
fi
#sprawdzamy, czy katalog DEST_DIR jest montowany poprzez NFS
NAZWA=$DEST_DIR
NAZWA=$(dir_nfs)
if [ ! -z "$NAZWA" ]
then
[ "$DEBUG" = "1" ] && \
echo "Katalog $DEST_DIR jest montowany poprzez NFS z maszyny $NAZWA"
pinguj
# jeśli host nie odpowiada
if [ $? -gt 0 ]
then
[ "$VERBOSE" = "1" ] && \
echo "- Maszyna $NAZWA nie odpowiada"
exit "$HOST_IS_DEAD"
fi
fi
[ "$DEBUG" = "1" ] && \
echo -e "\nWykonuję kopię pełną\n"
for katalog in `cat $TEMP/kopia0`
do
# Jeżeli jest to plik lub katalog
# ( -d zadziała również gdy jest to link symboliczny dla katalogu)
if [ -d $katalog -o -f $katalog ]
then
NAZWA=$katalog
#usuwamy (jeżeli istnieje) pierwszy znak '/'
katalog=$(remove_trailing_slash)
# dla kopii pełnej ustawiamy początkową część nazwy pliku
PRZEDROSTEK=$PRZEDROSTEK_FULL
NAZWA_PLIKU=$(nazwa_pliku)
NAZWA=$katalog
ROZMIAR_KATALOGU=$(rozmiar)
NAZWA=$DEST_DIR
FREE=$(wolne_miejsce)
[ "$VERBOSE" = "1" ] && \
echo -e "\nRozmiar katalogu $katalog - $ROZMIAR_KATALOGU bloków"
[ "$VERBOSE" = "1" ] && \
echo "Wolne miejsce na partycji z katalogiem $DEST_DIR - $FREE"
# Jeżeli dane będą kompresowane
if [ ! -z "$PACKER" ]
then
# jeżeli rozmiar katalogu do archiwizacji jest mniejszy od ilości
# wolnego miejsca w katalogu z plikami zarchiwizowanymi
if [ $ROZMIAR_KATALOGU -gt $FREE ]
then
# tutaj zmienić funkcję na _szacującą_ miejsce po kompresji
# w tej chwili piszemy komunikat o brkau miejsca - przecież
# nie wiemy czy pliki w ogóle dadzą się skompresować
# (np. jpg z gołymi babami ;)
echo -e "\n- Brak miejsca na utworzenie archiwum katalogu $katalog"
else
[ "$VERBOSE" = "1" ] && \
echo "Kopia pełna $katalog z kompresją $PACKER"
[ "$DEBUG" = "1" ] && \
echo "Kopia pełna katalogu $katalog przy użyciu programu do archiwizacji $ARCHIWIZER z opcjami $ARCHIWIZER_OPCJE z kompresją $PACKER"
case "$ARCHIWIZER" in
tar)
$ARCHIWIZER $ARCHIWIZER_OPCJE - $katalog \
| $PACKER >$DEST_DIR/$NAZWA_PLIKU
;;
cpio)
find $katalog | $ARCHIWIZER $ARCHIWIZER_OPCJE \
| $PACKER >$DEST_DIR/$NAZWA_PLIKU
;;
esac
fi
# jeżeli nie będziemy kompresować archiwum
else
if [ $ROZMIAR_KATALOGU -gt $FREE ]
then
echo -e "\n- Brak miejsca na utworzenie archiwum katalogu $katalog"
else
[ "$VERBOSE" = "1" ] && \
echo "Kopia pełna $katalog bez kompresji"
[ "$DEBUG" = "1" ] && \
echo "Kopia pełna katalogu $katalog przy użyciu programu do archiwizacji $ARCHIWIZER z opcjami $ARCHIWIZER_OPCJE bez kompresji"
case "$ARCHIWIZER" in
tar)
$ARCHIWIZER $ARCHIWIZER_OPCJE $DEST_DIR/$NAZWA_PLIKU $katalog
;;
cpio)
find $katalog | $ARCHIWIZER $ARCHIWIZER_OPCJE >$DEST_DIR/$NAZWA_PLIKU
;;
esac
fi
fi
# jeżeli zostało utworzone archiwum
NAZWA=$DEST_DIR/$NAZWA_PLIKU
if [ -f $NAZWA ]
then
[ "$VERBOSE" = "1" ] && \
echo "Rozmiar pliku $NAZWA_PLIKU - $(rozmiar)"
fi
else
echo -e "\n- Nie mogę odnaleźć katalogu $katalog"
fi
done
# jeżeli są jakieś pliki, dla których chcemy wykonać kopię różnicową
if [ -s $TEMP/kopia1 ]
then
[ "$DEBUG" = "1" ] && \
echo -e "\n\nWykonuję kopię różnicową"
for katalog in `cat $TEMP/kopia1`
do
if [ -d $katalog -o -f $katalog ]
then
NAZWA=$katalog
# Jeżeli mamy usuwać identyczne pliki
[ ! -z "$POPRZEDNI_USUWAJ" ] && \
poprzedni_plik
#usuwamy (jeżeli istnieje) pierwszy znak '/'
katalog=$(remove_trailing_slash)
# dla kopii pełnej ustawiamy początkową część nazwy pliku
PRZEDROSTEK=$PRZEDROSTEK_DZIEN
NAZWA_PLIKU=$(nazwa_pliku)
find $katalog -mtime -$[DZIEN -1] -type f -print >$TEMP/kopia.lista
LISTA="cat $TEMP/kopia.lista"
# jeżeli sa jakieś katalogi zmienione w ciągu ostatnich dni
if [ -s "$TEMP/kopia.lista" ]
then
[ "$VERBOSE" = "1" -o "$DEBUG" = "1" ] && \
echo -e "\nWykonuję kopię różnicową katalogu $katalog"
NAZWA=$DEST_DIR
FREE=$(wolne_miejsce)
NAZWA=$katalog
ROZMIAR_KATALOGU=$(rozmiar)
[ "$VERBOSE" = "1" ] && \
echo -e "Rozmiar katalogu $katalog - $ROZMIAR_KATALOGU bloków"
[ "$VERBOSE" = "1" ] && \
echo "Wolne miejsce na partycji z katalogiem $DEST_DIR - $FREE"
# jeżeli dane mają byś kompresowane
if [ ! -z "$PACKER" ]
then
if [ $ROZMIAR_KATALOGU -gt $FREE ]
then
# zmienić dla danych kompresowanych....
echo -e "\n- Brak miejsca na utworzenie archiwum katalogu $katalog"
else
[ "$DEBUG" = "1" ] && \
echo "Kopia różnicowa katalogu $katalog przy użyciu programu do archiwizacji $ARCHIWIZER z opcjami $ARCHIWIZER_OPCJE z kompresją $PACKER"
case "$ARCHIWIZER" in
tar)
$LISTA \
| xargs $ARCHIWIZER $ARCHIWIZER_OPCJE - \
| $PACKER >$DEST_DIR/$NAZWA_PLIKU
;;
cpio)
$LISTA \
| $ARCHIWIZER $ARCHIWIZER_OPCJE \
| $PACKER >$DEST_DIR/$NAZWA_PLIKU
;;
esac
fi
# jeśli dane nie będą kompresowane
else
if [ $ROZMIAR_KATALOGU -gt $FREE ]
then
echo -e "\n- Brak miejsca na utworzenie archiwum katalogu $katalog"
else
[ "$DEBUG" = "1" ] && \
echo "Kopia różnicowa katalogu $katalog przy użyciu programu do archiwizacji $ARCHIWIZER z opcjami $ARCHIWIZER_OPCJE bez kompresji"
case "$ARCHIWIZER" in
tar)
$LISTA \
| xargs $ARCHIWIZER $ARCHIWIZER_OPCJE $DEST_DIR/$NAZWA_PLIKU
;;
cpio)
$LISTA \
| $ARCHIWIZER $ARCHIWIZER_OPCJE >$DEST_DIR/$NAZWA_PLIKU
;;
esac
fi
fi
# jeżeli zostało utworzone archiwum
NAZWA=$DEST_DIR/$NAZWA_PLIKU
if [ -f $NAZWA ]
then
[ "$VERBOSE" = "1" ] && \
echo "Rozmiar pliku $NAZWA_PLIKU - $(rozmiar)"
if [ ! -z "$POPRZEDNI_USUWAJ" \
-a "$POPRZEDNI_ROZMIAR" ]
then
if [ $POPRZEDNI_NAZWA != $NAZWA \
-a "$(ls -lk $NAZWA|awk '{print $5}')" = "$POPRZEDNI_ROZMIAR" ]
then
diff $POPRZEDNI_NAZWA $NAZWA >/dev/null
if [ $? -eq 0 ]
then
echo "Usuwam plik $NAZWA"
rm "$NAZWA"
fi
fi
fi
fi
fi
else
echo -e "\n- Nie mogę odnaleźć katalogu $katalog"
fi
done
fi
[ "$DEBUG" = "1" ] && \
echo "sprawdzam czy kompresowac pliki tar/cpio w katalogu $DEST_DIR"
PACK=`grep ^KOMPRESOR= $TEMP/kopia.conf|awk -F'=' '{print $2}'`
if [ ! -z "$PACK" ]
then
[ "$VERBOSE" = "1" ] && \
echo "Wykonuje kompresje zbiorów w katalogu $DEST_DIR przy użyciu $PACK"
$PACK $DEST_DIR/*."$ARCHIWIZER"
fi
posprzataj
exit $OK
# Historia
#
# 2001.01.22
# wersja 0.78 - możliwość usuwania identycznych kopii różnicowych
# - lista zmienionych plików (find -mtime) jest robiona teraz
# jeden raz
#
# 2001.01.22
# wersja 0.77 - przygotowanie programu do uruchomienie jednocześnie kilku
# sesji
# - poprzedzenie komunikatów z błędami znakiem "-"
#
# 2001.01.22
# wersja 0.76 - pierwsza wersja udostępniona publicznie
Plik kopia.conf:
###################################################################
# #
# Plik konfiguracyjny skryptu do wykonywania kopii bezpieczeństwa #
# #
###################################################################
#Wymagane parametry:
#DEST_DIR=
DEST_DIR=/kopia2/KOPIE_SUN
#Opcjonalne parametry:
#
# DEBUG - tryb wyszukiwania błędów
# 1 - bardzo dużo komunikatów
# 0 - wyłączone
# Standardowo:
# DEBUG=0
DEBUG=0
# VERBOSE - tryb z komunikatami
# 1 - dużo komunikatów
# 0 - wyłączone
# Standardowo:
# VERBOSE=0
VERBOSE=1
# TEMP - katalog dla plików tymczasowych
# Standardowo:
# TEMP=/tmp
# UMASK - maska dla tworoznych plików
# Standardowo:
# UMASK=077
# PACKER - nazwa lub ścieżka dostępu do programu kompresującego
# Standardowo:
# PACKER=bzip2
# Inne możliwości:
# gzip - szybszy od bzip, ale mniejszy stopień kompresji
# compress - najwolniejszy i najmniejszy stopień kompresji
PACKER=compress
# ARCHIWIZER - nazwa lub ścieżka dostępu do programu archiwizującego
# Standardowo:
# PACKER=cpio
# Inne możliwości:
# tar
ARCHIWIZER=cpio
# ARCHIWIZER_OPCJE - opcja dla programu archiwizującego
# Standardowo:
# dla cpio: ARCHIWIZER_OPCJE="-o -a -H crc"
# dla tar: ARCHIWIZER_OPCJE="-cf"
# DATA_FMT - format daty (jak dla polecenia date +)
# Standardowo:
# DATA_FMT=%y%m%d_%H%M
#DATA_FMT=%y%m%d
# PRZEDROSTEK_FULL - przedrostek dla nazw plików przy kopii pełnej
# Standardowo:
# PRZEDROSTEK_FULL="full"
# PRZEDROSTEK_DZIEN - przedrostek dla nazw plików przy kopii różnicowej
# Standardowo:
# PRZEDROSTEK_DZIEN="dzien"
# POPRZEDNI_USUWAJ - czy mamy usuwać pliki, które są identyczne
# 1 - usuwanie aktualnego pliku archiwum jeśli poprzednie było
# identyczne
# Standardowo:
# POPRZEDNI_USUWAJ=""
POPRZEDNI_USUWAJ="1"
#
# Linia zaczynająca się cyfrą "0" oznacza wykonywanie kopii pełnej
# Linia zaczynająca się cyfrą "1" oznacza wykonywanie kopii różnicowej
# (a w rzeczywistości kopii plików zmienionych od początku miesiąca)
#
# kopia pełna
0 /local/defbank
#0 /local/zamosc
#0 /local/arch/zamosc
0 /home/linio/skrypty
0 /etc/passwd
# kopia różnicowa
1 /kernel
1 /TT_DB
1 /etc
1 /home
1 /install
1 /kernel
1 /opt
1 /platform
1 /sbin
1 /tmp
1 /usr
1 /var
1 /vol
1 /xfn
1 /y2k
1 /.dt
1 /mnt/hda11/var/spool/wwwoffle/ftp
Oczywiście, dostosowałem go do swoich potrzeb i jestem na etapie podpinania do Cron'a. Skrypt zawiera plik konfiguracyjny kopia.conf, który umieściłem w /etc/kopia, oraz podałem ścieżkę do wolnej (i do tego przeznaczonej) partycji podając ścieżkę dla DEST_DIR.
Działa fajnie i na razie nie zauważyłem jakichś problemów. Bardzo mi się przydał ze względu na swą prostotę i przejrzystość, oraz dodane komentarze.
Pozdrawiam, stoper.