Я сократил содержание сценария до одного цикла.Я думаю, что делаю то, что вы хотите.Я изменил все:
if [ something ]
then
на if [something ]; then
.Я думаю, что это сделало все отступы легче читать.Я удалил логику предварительного удаления и добавил цикл после завершения копирования.Таким образом, весь этот цикл пропал:
for filedest in $list2
do
#if [ ! -d $filedest ]
#then
check="true"
for filesrc in $list1
do
#if [ ! -d $filesrc ]
#then
if [ $filedest == $filesrc ]
then
check="false"
break
fi
#fi
done
if [ $check == "true" ]
then
if [ $test -eq 1 ]
then
echo "rm $dest/$filedest" >> $outerr
else
echo " ! "; rm $dest/$filedest #logic error here.
fi
fi
#fi
done
Еще одно важное изменение - все цитирование и изменение внутреннего разделителя полей (IFS).(Изменить: я изменил с помощью find
на glob (*
), поэтому нет необходимости менять IFS) Все это необходимо для того, чтобы вы могли обрабатывать имена файлов с пробелами в них.Вот что я закончил:
#!/bin/bash
out=/dev/stdout
#outerr=/dev/stderr
#outerr="test.txt"
function sync_dir
{
#This is our current subdirectory of $source and $dest.
#Note: In the original call we do not pass an arguement so $subdirs is blank.
#This means that "$source/$subdirs"* = "$source/"* for the origninal call.
local subdirs="$1"
#By removing these find calls, we can just use * and avoid making changes to the IFS
#local list1=`find "$source/$subdirs" -mindepth 1 -maxdepth 1 -name "*"`
#local list2=`find "$dest/$subdirs" -mindepth 1 -maxdepth 1 -name "*"`
#No need for find. Let * do all the work.
for filesrc in "$source/$subdirs"*; do
echo "$filesrc" >> $outsrc
#remove path from $filesrc
local filewithoutdir="$(basename "$filesrc")"
#if "$filesrc" is a directory
if [ -d "$filesrc" ]; then
#check to see if the destination is a directory. Make it if not...
if [ ! -d "$dest/$subdirs$filewithoutdir" ]; then
if [ $test -eq 1 ]; then
echo "mkdir \"$dest/$subdirs$filewithoutdir\"" >> $outerr
else
echo " ! "; mkdir "$dest/$subdirs$filewithoutdir" 2>> $outerr
fi
fi
#recursive call if we are dealing with a directory.
sync_dir "$subdirs$filewithoutdir/"
#else if not a file OR "$filesrc" is newer than the destination, copy it.
elif [ ! -f "$dest/$subdirs$filewithoutdir" -o "$filesrc" -nt "$dest/$subdirs$filewithoutdir" ]; then
if [ $test -eq 1 ]; then
echo "cp \"$filesrc\" \"$dest/$subdirs$filewithoutdir\"" >> $outerr
else
echo " ! "; cp "$filesrc" "$dest/$subdirs$filewithoutdir" 2>> $outerr
fi
fi
done
#Here we loop throught the destination directory
for filedest in "$dest/$subdirs"*; do
echo "$filedest" >> $outdest
local filewithoutdir="$(basename "$filedest")"
#If the files do not exist in the source directory, delete them.
if [ ! -e "$source/$subdirs$filewithoutdir" ]; then
if [ $test -eq 1 ]; then
echo "rm -f \"$filedest\" >/dev/null 2>&1" >> $outerr
else
#We allow this to fail and silence it because it may try to delete a directory.
echo " ! "; rm -f "$filedest" >/dev/null 2>&1
fi
fi
#if you want to remove files and directories use this, but this can be dangerous.
#if [ ! -e $source/$filewithoutdir ]; then
# if [ $test -eq 1 ]; then
# echo "rm -rf \"$filedest\" >/dev/null 2>&1" >> $outerr
# else
# echo " ! "; rm -rf "$filedest" 2>> $outerr
# fi
# rm -rf "$filedest" >/dev/null 2>&1
#fi
done
}
if [ $# -lt 2 ]; then
echo "" >> $out
echo " Not enough arguments passed to the script, try again next time." >> $out
echo "" >> $out
echo " Usage: " >> $out
echo " bash files_sync.sh [--t] SOURCE_NEW DESTINATION_OLD " >> $out
echo "" >> $out
echo " Options: --t just prints the modifications, without taking any action" >> $out
echo "" >> $out
exit 1
fi
test=0
if [ $# -eq 2 ]; then
#This will cause an issue when processing full path like /home/user/bla
#source=$(printf '%s\n' "$1" | sed 's/\///')
#dest=$(printf '%s\n' "$2")
#dest=$(printf '%s\n' "$2" | sed 's/\///')
source="$1"
dest="$2"
fi
if [ $# -eq 3 ]; then
if [ $1 == "--t" ]; then
echo "" >> $out
echo " Printing the suggested actions..." >> $out
test=1
source="$2"
dest="$3"
else
echo " What's your game, dude? Exiting. " >> $out
exit 20
fi
fi
if [ ! -d $source ]; then
echo "" >> $out
echo " Path $source does not exists or not a folder, exiting. " >> $out
echo "" >> $out
exit 2
else
echo "" >> $out
echo " (SOURCE) UP-TO-DATE FOLDER: $source" >> $out
echo "" >> $out
fi
if [ ! -d $dest ]; then
echo " Path $dest does not exists or not a folder, exiting. " >> $out
echo "" >> $out
exit 3
else
echo " (DESTINATION) TO BE SYNCHED FOLDER: $dest" >> $out
echo "" >> $out
fi
echo -n " Do you REALLY want to proceed? [y/N] : " >> $out
read choice
echo "" >> $out
if [ $choice == "n" ]; then
echo " Brilliant, bye!" >> $out
echo "" >> $out
exit 4
fi
if [ $choice == "y" ]; then
echo " Awesome! Let's get started ...."
outdest="testdest.txt"
echo " Writing DEST files into $outdest file" >> $out
> $outdest
outsrc="testsrc.txt"
echo " Writing SRC files into $outsrc file" >> $out
> $outsrc
outerr="testerr.txt"
echo " Writing operations into $outerr file" >> $out
>$outerr
#function call
sync_dir
#If we are not in test mode and errors have occured, they will be written to $outerr.
#This test (-s) checks to see that $outerr is not zero length (implies -e).
if [ ! $test -eq 1 -a -s $outerr ]; then
echo "WARNING: Errors have occured during the running of this script. See $PWD/$outerr for details" >> $out
fi
echo "" >> $out
echo ' --------- Sync COMPLETE ! -------------' >> $out
echo "" >> $out
else
echo "" >> $out
echo ' Not getting the answer. Exiting' >> $out
echo "" >> $out
fi
В настоящее время это не будет копировать содержимое каталога в источнике.Если это то, что вы хотите, вы можете поместить мясо этой вещи в функцию.Затем cd
в целевые каталоги и рекурсивный вызов функции для копирования содержимого подкаталога.
Редактирование: теперь реализована рекурсивная версия.Моя ранняя версия на самом деле неверна.Я неправильно понял -mindepth как -maxdepth.-maxdepth не позволил бы нам прочитать переданный первый каталог.Отредактированный код будет фактически работать с подкаталогами и каталогами полного пути.
Вы также заметите, что я добавил 2>> $outerr
к концу вызовов cp
, rm
и mkdir
.Это перехватит любой вывод в stderr и запишет его в $outerr
.Помните, что все эти команды могут потерпеть неудачу, поэтому важно как минимум отловить ошибки.В тестовом режиме вы печатали все фактические команды, которые будут использоваться в $outerr
.Вы не использовали его вообще, когда не в тестовом режиме, поэтому я заполняю его любыми ошибками, которые могут возникнуть во время обработки.В конце мы проверяем -s $outerr
, чтобы увидеть, были ли обнаружены какие-либо ошибки, и выложить небольшое предупреждениеЕсли вы хотите быть осторожнее, измените 2>> $outerr
на 2>> $outerr || exit 2
, чтобы принудительно завершить работу при любых ошибках.