Bash脚本实现Linux文件系统同步
在linux的工作环境中,不同的用户对应了不同的文件系统,我们可以通过群组等方式进行协同工作,当然这 些不同的方式也各有利弊。这篇文章主要针对各用户各自操作自己的文件系统,并在修改后 进行同步来进行协同的方式。 脚本需要帮助我们做一些机械的、简单的工作,比如将文件系统逐项比对并生成日志文件,这种工作在文件系统十分复杂的情况下工作量巨大,所以完全可以交给计算机来做。但是有些情况我们不能完全依赖于计算机,比如由于小组成员事先没有沟通好,两个用户分别把同一个文件按照自己的方案修改了,这样计算机就无法识别出我们应该保留哪个文件、删除哪个文件,而需要我们的小组成员商讨来决定。我们把这种情况叫做冲突。如果没有发生冲突,我们将文件的大小、权限、上次修改时间等信息进行比较即可,这种比较归根结底只是对字符串进行的比较,不管文件多大,计算机处理起来都非常的迅速。但当发生冲突时,我们要比较的则是两个文件的具体内容,尽管有现成的diff函数,但是对大型文件的内容比较也是十分耗费时间的。但好在这两种比较方式并不矛盾,我们对关键信息的比较既可以判断文件是否被修改,也可以判断文件是否发生了冲突,因为我们的比较不是两个文件系统进行比较,而是两个文件系统分别与日志文件进行比较;当两个文件系统的关键信息均与日志文件不同时,我们就可以认定两个用户均对该文件进行了修改,即针对这一文件发生了冲突。但是如果存在这种情况,即两用户对同一文件进行了同样的修改,或是两用户分别刷新了两文件的上次修改时间,那么这种冲突本身是无意义的,这种情况叫做*假冲突**计算机应该自行对其判断并处理,以节省人为判断的时间。这个问题解决起来也十分简单,只要diff函数没有输出就好了。
```bash
#!/bin/bash
IFS=$'\n\n'
Path_A=~/LO14_projet/a
Path_B=~/LO14_projet/b
P=.
Path_LOG=~/LO14_projet/log.log
function compare()
{
for i in $(ls -l $1 | sed '1d')
do
name=$(echo $i | awk '{print $9}')
Path_a=$1/$name
Path_b=$2/$name
j=$(ls -l $2 | grep ".*\s$name$")
p=$3/$name
log_A=$(echo $i $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}')
log_B=$(echo $j $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}')
log=$(grep "^$name\s.*\s$3$" $4)
num_l=$(grep -n "^$name\s.*\s$3$" $4 | cut -d ':' -f 1) #日志中该文件所在行号
if [ -d $Path_a ] && [ -d $Path_b ]
then
compare $Path_a $Path_b $p $4
elif [ -d $Path_a ] || [ -d $Path_b ]
then
echo "There is a crash between $Path_a and $Path_b, and one of them is a directory"
read -p "Do you want to delete one of them?(y/N)" d
if [ $d == y ] ||[ $d == Y ]
then
read -p "You want to delete the file, the directory or the both(0 means delete both)?(0/d/f)" b
if [ $b == 0 ]
then
rm -rf $Path_a
rm -rf $Path_b
sed -i ''$num_l'd' $4
elif [ $b == d ]
then
if [ -d $Path_a ]
then
rm -rf $Path_a
cp $Path_b $1
touch $Path_b #更新b的上次修改时间
k=$(ls -l $2 | grep ".*\s$name$") #更新logb
log_B=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新logb
sed -i ''$num_l'c '$log_B'' $4
else
rm -rf $Path_b
cp $Path_a $2
touch $Path_a #更新a的上次修改时间
k=$(ls -l $1 | grep ".*\s$name$")
log_A=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新loga
sed -i ''$num_l'c '$log_A'' $4
fi
elif [ $b == f ]
then
if [ -f $Path_a ]
then
rm $Path_a
cp -r $Path_b $1
sed -i ''$num_l'c '$log_B'' $4
else
rm $Path_b
cp -r $Path_a $2
sed -i ''$num_l'c '$log_A'' $4
fi
else
echo 'This input is not in a right way, so the crash is not solved'
fi
elif [ $d == N ] || [ $d == n ]
then
echo 'The crash is not solved'
else
echo 'This input is not in a right way, so the crash is not solved'
fi
else
if [ "$log_A" == "$log" ]
then
if [ "$log_B" != "$log" ]
then
rm $Path_a
cp $Path_b $1
touch $Path_b
k=$(ls -l $2 | grep ".*\s$name$")
log_B=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新logb
sed -i ''$num_l'c '$log_B'' $4
fi
else
if [ "$log_B" == "$log" ]
then
rm $Path_b
cp $Path_a $2
touch $Path_a
k=$(ls -l $1 | grep ".*\s$name$")
log_A=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新loga
sed -i ''$num_l'c '$log_A'' $4
else
if [ -z "$(diff $Path_a $Path_b)" ]
then
echo "There is a crash between $Path_a and $Path_b, but it's not a real crash"
rm $Path_b
cp $Path_a $2
touch $Path_a
k=$(ls -l $1 | grep ".*\s$name$")
log_A=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新loga
sed -i ''$num_l'c '$log_A'' $4
else
echo "There is a crash between $Path_a and $Path_b, and both of them are files, the difference is as followed"
diff $Path_a $Path_b
echo "Do you want to delete one of them?(y/N)"
read d
if [ $d == y ] || [ $d == Y ]
then
read -p "Which one do you want to delete(0 means delete both)?(0/1/2)" b
if [ $b == 0 ]
then
rm $Path_a
rm $Path_b
sed -i ''$num_l'd' $4
elif [ $b == 1 ]
then
rm $Path_a
cp $Path_b $1
touch $Path_b
k=$(ls -l $2 | grep ".*\s$name$")
log_B=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新logb
sed -i ''$num_l'c '$log_B'' $4
elif [ $b == 2 ]
then
rm $Path_b
cp $Path_a $2
touch $Path_a
k=$(ls -l $1 | grep ".*\s$name$")
log_A=$(echo $k $3 | awk '{printf "%s\t%s\t%s\t%s\t%s\t%s\t%s",$9,$1,$5,$6,$7,$8,$10}') #更新loga
sed -i ''$num_l'c '$log_A'' $4
else
echo 'This input is not in a right way, so the crash is not solved'
fi
elif [ $d == N ] || [ $d == n ]
then
echo 'The crash is not solved'
else
echo 'This input is not in a right way, so the crash is not solved'
fi
fi
fi
fi
fi
done
}
compare $Path_A $Path_B $P $Path_LOG
echo "The synchronization of $Path_A and $Path_B has been completed"
``
虽然脚本很短,但由于是初学者,在写脚本的时候也出过许多问题,例如在复制文件时,被同步的文件的上次修改时间为脚本执行的时间,而原本文件的时间就再次与它不同了。我们如果对其中与日志文件时间不同的文件进行了修改,而希望脚本对其进行自动同步,那么脚本就会把这种现象判断为冲突,显然与我们的期望不同。这个问题虽然很小但不易发现,其实只要在脚本中用touch操作进行时间的刷新即可。 希望大家在评论区多多交流,可自由转载但请注明出处。