вторник, 28 февраля 2017 г.

Backup файлов с сохранением заданной структуры папок и фильтрацией по расширениям файлов

Возникла необходимость периодически сохранять файлы работ отдела на некоторый удаленный сервер в случае непредвиденных обстоятельств. Задача простая и не простая одновременно. И так - техническое задание:
1. Копировать только файлы заданных расширений, для уменьшения объема занятого места.
2. Сохранить из общего пути местонахождения файлов только конечные папки, если возникнет необходимость сжать выборочно.
3. Копирование ведется накопительно, старые файлы не удаляются, новые добавляются, если изменились имеющееся - перезаписываются.
4. Используется системные утилиты, на случай повторения такого сценария где либо еще.
5. Место положения и место хранения может быть разным и хозяева данных тоже.
И так, система - Debian Jessie, язык сценария - bash, управление периодичностью служба cron.
Небольшое отступление, в момент написания скрипта были использованы всевозможные варианты фильтрации расширений с использованием grep.

indir=$PWD/in;
outdir=$PWD/out;
tru_ex=( "jpg"
         "tif"
         "odt" );
find -type 'f' |grep -E "$(echo -e ${tru_ex[@]}|sed 's/\ /|/g')"

или

indir=$PWD/in;
outdir=$PWD/out;
tru_ex=( "jpg"
         "tif"
         "odt" );
find -type 'f' |grep -E "$(echo -e ${tru_ex[@]}|sed 's/\ /|/g')"|xargs -I % cp -r -f  --parent "%" -t  $outdir;
- тут проблема с утилитой xargs, не "переносит" одинарные кавычки...

был и вариант из серии использования массива параметров утилиты find:

indir=$PWD/in;
outdir=$PWD/out;
tru_ex=( "jpg"
         "tif"
         "odt" );
fexec=();
for ((i_exc=0; i_exc != ${#tru_ex[@]}; i_exc++))
       do
        if [ $i_exc != $((${#tru_ex[@]}-1)) ] 
            then  parm=" -o -name";
            else parm="";
        fi
        fexec[${#fexec[@]}]=" *.${tru_ex[$i_exc]} $parm";
done
extract=$(echo "find -type f" "(" "-name " "$(echo -e ${fexec[@]})" ")")$(echo " -exec cp -f -r --parent --target-directory=$outdir {} ;");
#"
cd $indir

$extract

- который при большом количестве указанных расширений - 
просто "ложит" систему....!

тот скрипт который получился в конечном итоге, выполняет все требования и не перегружает систему при копировании. Код ниже и ссылка для скачивания.

#!/bin/bash
##  author (c) by koshuba v.o. - open technologies
## The script is copying files from the given extensions .. (weak version of the processor)
#date
rdate=`date +%d.%m.%y_%H:%M`
#logfile
log=/var/log/syslog

#the master directory on the server
smbuser=( user1 user2 user3 user4 );
smbgroup=( group1 group2 group3 group4 )
## allowed extensions
tru_file=( "bmp"
    "doc"
    "docx"
    "jpg"
    "mdb"
    "odb"
    "odt"
    "pdf"
    "PST"
    "QST"
    "shx"
    "tif"
    "ttf"
    "txt"
    "xls"
    "xlsx"
    "xml"
    "rtf"
    "ods" );
# synchronize directories
get_dir=( "/work/share"
  "/work/share"
  "/share2"
  "/share2" );
# directly copied directories
read_dir=( "work1"
  "work2"
  "work3"
  "work4" );
# directories to backup files
put_dir=( "/arhive/copy_share"
  "/arhive/copy_share"
  "/arhive/copy_share"
  "/arhive/copy_share" );
#------------------------------------------------
echo `date +%d.%m.%y_%H:%M` "Begin syncing files on the server...">>$log
# Copy the specified directory on the server and update Regulations
# We will perform the cycle until the end of the array of names
for ((i_names=0; i_names != ${#get_dir[@]}; i_names++))
    do
    cd ${get_dir[$i_names]};
# We will perform the cycle until the end of the array of allowed extensions
    for ((i_ex=0; i_ex != ${#tru_file[@]}; i_ex++))
 do
 find ${read_dir[$i_names]} -type 'f' -name "*.${tru_file[$i_ex]}" -exec cp -r -f --parent -t ${put_dir[$i_names]} '{}' \;
    done
# Assign user permissions
chmod -R 0666 ${put_dir[$i_names]}/${read_dir[$i_names]};
chmod -R ugo+X ${put_dir[$i_names]}/${read_dir[$i_names]};
chown -R ${smbuser[$i_names]}:${smbgroup[$i_names]} ${put_dir[$i_names]}/${read_dir[$i_names]};
done

echo `date +%d.%m.%y_%H:%M` "Leaving syncing files on the server...">>$log
exit 0


Скачать можно тут...
...и да прибудет с вами великий backup! 😄

пятница, 20 января 2017 г.

BASH: Скрипт автоматизированной архивации каталогов баз данных 1С через samba


Думаю многим Администраторам приходится решать задачи по автоматизации различных архивов баз данных или прочих "данных" и данный скрипт поможет упростить по крайней какую то часть рутины. Собственно скрипт писался для копирования и архивации баз данных 1C с сервера Windows на сервере Linux, для дальнейшего использования программистами уже из архива. Скрипт делает архив каждый день, каждую неделю и удаляет ежедневные, каждый месяц - удаляет дневные и недельные. Есть возможность принудительно вызывать как недельную так и месячную архивацию. Все параметры с комментариями задаются в начале скрипта. В работе скрипт подключается к сетевому диску Windows/Linux через службу samba копирует указанные каталоги во временный каталог, после чего сжимает их с указанными именами архивов (привязаны к именам каталогов баз) с добавлением текущей даты архивации.
В скрипте есть параметр "входа" - это если после подключения сетевого диска необходимо еще и зайти в какой то специальный каталог и только потом можно копировать каталог базы. Такое например бывает если место расположения баз различное как по ресурсам так и по путям "входа".
Ниже код скрипта на языке Bash.
_________________________________________________________________________________
#!/bin/bash
## It is a system script for 1c database backups 
## author (c) by koshuba v.o. - open technologies
## licence MIT 2016
export LANG=ru_RU.UTF-8
## 
option=$1
rdate=$(date +%c);
arh_date=$(date +%d_%m_%y);
log_arh="/var/log/syslog";

## values read devices & index array values

host_smb="10.10.10.4";                                           #: хост подключения
login_smb=( '"Администратор" "mypass"' );            #: логин и пароль к ресурсу
name_db=( "Base1" "Base2" "Base3" "Base4" );             #: имена каталогов баз данных
name_arh=( "base1_" "base2_" "base3_" "base4_" );     #: имена суточных архивов + дата на момент архивации
path_mnt="/mnt/read_smb";                                    #: директория для монтирования ресурса
path_main_arh="/arhbase";                                     #: основной каталог архивов
path_arh=( "day" "week" "month" );                        #: отдельные каталоги суточных, недельных и месячных архивов
path_tmp="/home/temp";                                          #: временная папка для архивации баз
path_in_cd=( "" );                                                      #: путь входа для копирования
policy=( "user:sambashare" )                                   #: права на архивы


## values for db arhives

read_smb=( "E$"  "$F");       #: ресурс где находятся базы данных - индексы ниже привязаны к нему
## <>
link_db=( '"0" "1"'  '"2" "3"' );                                                #: индексы имен каталогов с базами
link_arh=( '"0" "1"'  '"2" "3"' );                                               #: индексы имен архивов для сжатия
link_policy=( '"0" "0"'  '"0" "0"' )                                            #: индексы права на архивы
link_in_cd=( '"0" "0"'  '"0" "0"' )                                             #: индексы входа в каталог баз
link_login_smb=( '"0" "0"'  '"0" "0"' );                                    #: индексы логин и пароль к ресурсу                                          
                                                                                                                                                             
## tmp                                                                                                                                                       
tmp_smb="";                                                           #: текущий share для чтения                        
tmp_db=();                                                               #: текущий список каталогов баз                  
tmp_login=();                                                           #: текущий логин к ресурсу                           
tmp_nmdb=();                                                          #: текущий список имен архивов                 
tmp_pl=();                                                                #: текущие политики                                      
tmp_in_cd=();                                                          #: текущий каталог входа к базам                                             
                                                                                                                                                             
## defaults                                                                                                                                                 
reports=();                                                                #: массив для сообщений                               
event_type="";                       #: тип события для выполнения операции, за день, за неделю и.т.д.            
                                                                                                                                                             
## functions & operations                                                                                                                                    
## develop mode ...                                                                                                                                          
operation_day=( "checkLock" "mountSmb" "arhDb" "umountSmb" "lockOff" );                                        
operation_week=( "checkLock" "mountSmb" "arhDb" "umountSmb" "clearArh" "lockOff" );                    
operation_month=( "checkLock" "mountSmb" "arhDb" "umountSmb" "clearArh" "lockOff" );                   
operation_help=( "printInfo" );                                                                                                                    
execute_func=();                                                                                                                                             
## logic executor values
iFs=();
logic=();
value_in="";
lEnd=1;

##..............................................................................

## -@F logic executor
function eXlogic() {
lEnd=1;
if [[ ${#iFs[@]} -eq 0 ]]||[[ ${#iFs[@]} != ${#logic[@]} ]]
    then echo "exit";
         exit 0;
fi

local exfunc=();

for ((lg_index=0; lg_index != ${#iFs[@]}; lg_index++))
 do
    ## !! debug operation...
    ## echo "eXlogic = execution: function ${iFs[$lg_index]} : index=$lg_index";
    local lg=$(echo $((${iFs[$lg_index]})) );
    local exfunc=( ${logic[$lg_index]} );
    local runfunc=$(echo ${exfunc[$lg]}| sed 's/\"//g');
    $runfunc;
    if [[ $lEnd == 0 ]] 
        then lg_index=$((${#iFs[@]}-1)); 
    fi
done
iFs=();
logic=();
value_in="";
}

##..............................................................................

## -@F function check lock file
function checkLock() {
if [ ! -f /tmp/run-arh.lok ]
    then 
        echo >/tmp/run-arh.lok;
    else
        reports=();
        reports[${#reports[@]}]="обнаружен признак занятости, архивация баз по событию < $event_type > - не выполнена!";
        makeErr;
fi

}


##..............................................................................

## -@F function check lock file
function lockOff() {
rm -f /tmp/run-arh.lok;
reports=();
reports[${#reports[@]}]="архивация баз по событию < $event_type > - выполнена успешно."
writeToLog;
}

##.............................................................................

## -@F function mount share
function mountSmb(){

if [ ! -d $path_mnt ]

    then
        mkdir -p $path_mnt;
fi

this_login=( ${login_smb[$(echo ${tmp_login[0]}| sed 's/\"//g')]} );

## проверка на смонтированный ресурс, если есть - выход с ошибкой!
        test_mount=$(df -h|grep $host_smb|wc -m);

        if [ $test_mount != 0 ]

            then
                reports=();
                reports[${#reports[@]}]="обнаружен примонтированный ресурс, архивация баз по событию < $event_type > - не выполнена!";
                makeErr;
            else
            mount -t cifs //$host_smb/$tmp_smb $path_mnt -o gid=1000,uid=1000,file_mode=0666,dir_mode=0777,user=$(echo ${this_login[0]}| sed 's/\"//g'),pass=$(echo ${this_login[1]}| sed 's/\"//g');
        fi


##.............................................................................

## -@F function umount share
function umountSmb(){
## проверка на смонтированный ресурс, если есть - откючаем...
        test_mount=$(df -h|grep $host_smb|wc -m);
        if [ $test_mount = 0 ]
            then
                reports=();
                reports[${#reports[@]}]=" не обнаружен примонтированный ресурс, по событию < $event_type > - прекращена!";
                makeErr;
            else
            umount $path_mnt;
        fi
}

##................................................................................

## -@F function copy end archive bases
function arhDb(){

local path_arh_in="";


iFs=(   "$(echo -n $event_type|sed 's/day//g'|wc -m) == 0"

        "$(echo -n $event_type|sed 's/week//g'|wc -m) == 0"
        "$(echo -n $event_type|sed 's/month//g'|wc -m) == 0" );

logic=( '"" "arhDay"'

        '"" "arhWeek"'
        '"errArh" "arhMonth"'
        );

    function arhDay() {

    lEnd=0;
    path_arh_in=$path_main_arh/${path_arh[0]};
    makeArh;
    }

    function arhWeek() {

    lEnd=0;
    path_arh_in=$path_main_arh/${path_arh[1]};
    makeArh;
    }

    function arhMonth(){

    lEnd=0;
    path_arh_in=$path_main_arh/${path_arh[2]};
    makeArh;
    }


    function makeArh() {

##
    for ((index_make=0; index_make != ${#tmp_db[@]}; index_make++))
        do
    # текущий каталог входа к базам
    local in_cd="${path_in_cd[$(echo ${tmp_in_cd[$index_make]}| sed 's/\"//g')]}";

    # получаем имя базы для копирования

    local in_db="${name_db[$(echo ${tmp_db[$index_make]}| sed 's/\"//g')]}";
    # копируем данную базу во временный каталог
    if [ ! -d $path_tmp ]
        then
        mkdir -p $path_tmp
        chmod -R 0666 $path_tmp;
        chmod -R ugo+X $path_tmp;
    fi
    if [ ! -d $path_tmp/$in_db ]
        then
        mkdir -p $path_tmp/$in_db
        chmod -R 0666 $path_tmp/$in_db;
        chmod -R ugo+X $path_tmp/$in_db;
    fi
    cd $path_mnt/$in_cd;
    ##cp -f -R $in_db $path_tmp;
    ## исключаем блокированные файлы базы 1с
    find $in_db -type 'f' | grep -v .cfl|grep -v .cgr| xargs -n 1 -I % cp -f -R --parents  "%" $path_tmp;
    cd
    #............................................
    # получаем имя архива для данной базы
    local arh_dbname="$path_arh_in/${name_arh[$(echo ${tmp_nmdb[$index_make]}| sed 's/\"//g')]}$arh_date.7z";
    if [ ! -d $path_arh_in ]
        then
        mkdir -p $path_arh_in;
        chmod -R 0666 $path_arh_in;
        chmod -R ugo+X $path_arh_in;
    fi
    # архивируем базу в заданный каталог..
    cd $path_tmp && 7z -t7z -mx=9 -r -ssc a $arh_dbname $in_db $2>/dev/null;
    cd
    # устанавливаем права на базы
    chown -R ${policy[$(echo ${tmp_pl[$index_make]}| sed 's/\"//g')]} $arh_dbname ;
    #............................................
    # удаляем временную копию текущей базы
    rm -f -R $path_tmp/$in_db;
    #............................................
    done
    }

    function errArh(){

    lEnd=0;
    reports=();
    reports[${#reports[@]}]="архивация по событию < $event_type > не выполнена...";
    printInfo;
    }

eXlogic;

}

##................................................................................

function clearArh() {
local path_arh_clr="";

iFs=(   "$(echo -n $event_type|sed 's/week//g'|wc -m) == 0"

        "$(echo -n $event_type|sed 's/month//g'|wc -m) == 0" );

logic=( '"" "clearDay"'

        '"errClear" "clearWeek"'
        );

    function clearDay() {

    lEnd=0;
    path_arh_clr=$path_main_arh/${path_arh[0]};
    clrOldDb;
    # удаляем архивы по имени +маска
    }

    function clearWeek() {

    lEnd=0;
    path_arh_clr=$path_main_arh/${path_arh[0]};
    clrOldDb;
    path_arh_clr=$path_main_arh/${path_arh[1]};
    clrOldDb;
    # удаляем архивы по имени +маска
    }

    function errClear(){

    lEnd=0;
    reports=();
    reports[${#reports[@]}]="удаление по событию < $event_type > не выполнено...";
    writeToLog;
    printInfo;
    # обработка ошибок если есть...
    }

function clrOldDb() {

for ((index_clr=0; index_clr != ${#tmp_db[@]}; index_clr++))
        do
    # получаем имя базы для удаления
    local clr_db="${name_arh[$(echo ${tmp_db[$index_clr]}| sed 's/\"//g')]}";
    rm -f $path_arh_clr/$clr_db*;
done
}

eXlogic;

}


##................................................................................

##--@F make all errors
function makeErr() {
        reports[${#reports[@]}]="операция по событию < $event_type > не выполнена!";
 printInfo;
 writeToLog;
 exit 0;
 exit 1;
}

##................................................................................

##--@F make all messages
function printInfo() {
value_in="$option";
iFs=(   "$(echo -n $value_in|wc -m) == 0"
        "$(echo -n $value_in|sed 's/--help//g'|wc -m) == 0" 
        "$(echo -n ${#reports[@]}) == 0" );

logic=( '"" "pInone"'

        '"" "pIhelp"'
        '"pIdf" "pInone"' );


function pInone() {

    lEnd=0;
    clear
    echo
    ##echo "psec:$(($(date +%s%3N)-$settime))";
    exit 0;
}

function pIhelp() {

    lEnd=0;
    clear
    reports=();
    reports[${#reports[@]}]="Архивация за один день: --d"; 
    reports[${#reports[@]}]="Архивация на конец недели (удалаются все архивы за день и содается архив на конец недели): --w";
    reports[${#reports[@]}]="Архивация на конец месяца (удалаются все архивы за день и за неделю затем содается архив на конец месяца): --m";
    pIdf;
    exit 0;
}

## default function last eXlogic..

function pIdf() {
    for ((rpt_index=0; rpt_index != ${#reports[@]}; rpt_index++))
        do
    echo   "${reports[$rpt_index]}";
    done
    exit 0;
    }
eXlogic;
}

##................................................................................

##--@F make all messages to log file
function writeToLog() {
for ((wrl_index=0; wrl_index != ${#reports[@]}; wrl_index++))
        do
    echo "$rdate - arh_db_zraid: ${reports[$wrl_index]}" >> $log_arh;
done
}

##................................................................................

##--@F executor
## обработчик операций..
function executor() {

if [[ ${#execute_func[@]} -eq 0 ]] 

    then echo "exit";
         exit 0; 
fi
for ((ex_index=0; ex_index != ${#execute_func[@]}; ex_index++))
 do
    ## !! debug operation...
    ## echo "execution: function ${execute_func[ex_index]}"
 ${execute_func[ex_index]};
done
}

##................................................................................

## обработка вызовов операций в зависимости от количества указанных ресурсов для чтения баз
function agent() {
for ((step_i=0; step_i != ${#read_smb[@]}; step_i++))
 do
tmp_smb=${read_smb[$step_i]};
tmp_db=( ${link_db[$step_i]} );
tmp_nmdb=( ${link_arh[$step_i]} );
tmp_pl=( ${link_policy[$step_i]} );
tmp_in_cd=( ${link_in_cd[$step_i]} );
tmp_login=( ${link_login_smb[$step_i]} );
executor
done
}


## events

case "$option" in

## the arhive day bases

"--d" | "--d" )
testday=$(date +%d|grep 01|wc -m);
    if [ "$testday" != 0 ]
        then
        event_type="month";
        execute_func=( ${operation_month[@]} );
        agent;
    #иначе делаем ежедневный архив
        else
        event_type="day";
        execute_func=( ${operation_day[@]} );
        agent;
    fi
exit 0
;;

## the arhive week bases

"--w" | "--w" )
testday=$(date +%d|grep 01|wc -m);
    if [ "$testday" != 0 ]
        then
        event_type="month";
        execute_func=( ${operation_month[@]} );
        agent;
    #иначе делаем еженедельный архив
        else
        event_type="week";
        execute_func=( ${operation_week[@]} );
        agent;
    fi
exit 0
;;

## the arhive month bases

"--m" | "--m" )
event_type="month";
execute_func=( ${operation_month[@]} );
agent;
exit 0
;;

## help

"--help" | "--help" )
execute_func=( ${operation_help[@]} );
executor
exit 0
;;

* )

# selecting defaults.
option="--help";
execute_func=( ${operation_help[@]} );
executor
exit 1
;;
esac

Просто скачать можно здесь: https://github.com/vixfree/arhbases