-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathcompress-data.sh
More file actions
449 lines (404 loc) · 15.2 KB
/
compress-data.sh
File metadata and controls
449 lines (404 loc) · 15.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
#!/bin/bash
################################################################################
## Bash script for file or directory compression ##
################################################################################
## 1. Configuration variables
## $srcName - Source, file or directory to compress.
## $srcDir - Directory where the source resides.
## $runDir - Runtime directory. Lock and log files reside here.
## $outDir - Directory where the archive will be placed.
## $archDir - Directory where the previous archives will be placed.
## $archName - Archive file name.
## [ example: "archive_$(date +"[%Y.%m.%d - %H:%M:%S]")" ]
## $logName - Log file name.
## $lockCheck - Check for lock file or not.
## If you have condition(s) in which creation of an archive is not
## recommended or fatal (e.g. while creating snapshot, directory must not
## be tempered with in any way) and the process which is running prior to
## archivation (rsnapshot, rsync, rdiff etc.), can create a lock file,
## you must switch this check ON and fill out a name for a lock file,
## to prevent integrity violation.
## [ default: true ]
## $lockName - Lock file name.
## $lockSleep - How much time to wait until next try (in milliseconds).
## [ default: 600 ] - 10 minutes.
## $lockWait - How many tries before script stop.
## [ default: 12 ] - Retry for 2 hours if $lockSleep = 600
## oldArchDaysBack - How much time (in days) into the past, search must look
## for old archive files inside the vault ($archDir) for deleting the oldest.
## [ default: 30 ] - One month.
## @WARNING! If you set $maxOldArch to say 10 and you run archivation process
## say every 24 hours, but your $oldArchDaysBack is set to 7, script will
## not be able to account for 3 oldest archive files, so your vault can
## grow more than 10!
## maxOldArch - How much old archive files must be kept inside the vault.
## [ default: 30 ]
## @WARNING! Do not set higher than $oldArchDaysBack if you run this script
## daily!
## $mailSendSucc - Enable mail sending on success.
## $mailSendFail - Enable mail sending on fail.
## $mailFileName - Mail file name.
## $mailTo - To which e-mail messages must be sent.
## $mailSubject - Subject of the message.
## $stdType - Sets output to console and or log file.
## [ default: "cl" ] { "cl" = console & log, "l" = log only }
## $txtFormat - Allow text formating (bold and colored text).
## [ default: true ]
## $debug - Enable debugging or not.
## [ default: true ]
## $timeStamp - Timestamp format.
## [ default: "[%Y.%m.%d - %H:%M:%S]" ]
## $compressor - Compressor and it's params.
## [ default: "xz -T 4 -9 -c" ]
## $archExt - Archive extension, depending on $compressor setting.
## [ default: ".tar.xz" ]
##
## 2. Helper functions
## msg() - Prints messages.
## [ example: msg "Archive file name is: %s\n" "$arcname" ]
## tf() - Formats text.
## tStamp() - Prints timestamp.
## [ example: "$(tStamp "[%Y.%m.%d - %H:%M:%S]")" ]
## [ fallback: "${timeStamp}" ]
## secToTime() - Turns seconds into readable time (e.g. 3h 45m 21s).
## sendMail() - Sends e-mails.
## ifDebug() - Checks if debuging is enabled.
## ifLock() - Checks if lock file check is enabled.
## succ() - Process success output.
## fail() - Process fail output.
## 3. Functions
## checkConf() - Validates configuration.
## checkLock() - Checks for lock file.
## checkForOldArch() - Checks old archive files.
## execComp() - Executes compression and assigns execution time to $execTime.
## size() - Gets object size values.
## @Takes two parameters, object and presentation format
## (h - human readable, b - bytes)!
## [ example: "$(size "$src" "b")" ]
## compRatio() - Gets compression ratio.
## @Takes two parameters, source and archive!
## [ example: "$(compRatio "$src" "$archive")" ]
## compInf() - Outputs compression info.
## [ example: compInf $src $archive ]
################################################################################
## =========================== ##
## Set configuration variables ##
## =========================== ##
srcName="test-file"
srcDir="/tmp/"
runDir="/tmp/run/"
outDir="/tmp/out/"
archDir="/tmp/vault/"
archName="arch"
logName=$archName
lockCheck=true
lockName=$archName
lockSleep=600
lockWait=12
oldArchDaysBack=30
maxOldArch=10
mailSendSucc=false
mailSendFail=true
mailFileName=$archName
mailTo="your@email.address"
mailSubjectSucc="$0 says: Process has finished successfuly!"
mailSubjectFail="$0 says: Warning! Process has failed!"
stdType="cl"
txtFormat=true
debug=true
## Do not change this variables if you don't know how!
timeStamp="[%Y.%m.%d - %T]"
compressor="xz -T 4 -9 -c"
archExt=".tar.xz"
## ======================================= ##
## WARNING! Do not modify past this point! ##
## ======================================= ##
## ---------------- ##
## Global variables ##
## ---------------- ##
export TERM=xterm
TIMEFORMAT="%E"
runDir=${runDir%/} ; srcDir=${srcDir%/} ; srcName=${srcName%/} ## Deslashify.
outDir=${outDir%/} ; archDir=${archDir%/} ## Deslashify.
src="$srcDir/$srcName" ## Full path to source.
archiveFN="$archName$archExt" ## Archive file name and extension.
archive="$outDir/$archiveFN" ## Full path to archive.
logFile="$runDir/$logName.log" ## Full path to log file.
logFileF="$runDir/$logName.f.log" ## Full path to log file.
lockFile="$runDir/$lockName.lock" ## Full path to lock file.
mailFile="$runDir/$mailFileName.mail" ## Full path to mail file.
execute=0 ## Allow execution.
execTime="" ## Compression execution time.
## ------------- ##
## Initial setup ##
## ------------- ##
exec 3>&1 1>>$logFile 2>&1 ## Modifies std output.
## ---------------- ##
## Helper functions ##
## ---------------- ##
## Prints messages.
msg() { [[ $stdType == "cl" ]] && printf "$@" | tee /dev/fd/3 || printf "$@" ; }
## Text formating.
tf() {
if [[ $txtFormat == true ]] ; then
res=""
for ((i=2; i<=$#; i++)) ; do
case "${!i}" in
"bold" ) res="$res\e[1m" ;;
"underline" ) res="$res\e[4m" ;;
"reverse" ) res="$res\e[7m" ;;
"red" ) res="$res\e[91m" ;;
"green" ) res="$res\e[92m" ;;
"yellow" ) res="$res\e[93m" ;;
esac
done
echo -e "$res$1\e[0m"
else
echo "$1"
fi
}
## Sets timestamp.
tStamp() {
if [[ -n ${1} ]] && [[ ! -n ${2} ]] ; then
date +"${1}"
elif [[ -n ${1} ]] && [[ -n ${2} ]] ; then
date -d "${2}" +"${1}"
else
date +"${timeStamp}"
fi
}
## Seconds to readable time.
secToTime() {
timeInSec=$1
if [[ $timeInSec -ge 0 ]] && [[ $timeInSec -le 59 ]]; then
echo "${timeInSec}s"
elif [[ $timeInSec -ge 60 ]] && [[ $timeInSec -le 3599 ]]; then
m=$(( timeInSec / 60 ))
s=$(( timeInSec % 60 ))
echo "${m}m ${s}s"
elif [[ $timeInSec -ge 3600 ]] && [[ $timeInSec -le 86399 ]]; then
h=$(( timeInSec / 3600 ))
m=$(( (timeInSec % 3600) / 60 ))
s=$(( (timeInSec % 3600) % 60 ))
echo "${h}h ${m}m ${s}s"
fi
}
## Sends e-mail.
sendMail() {
if [[ ! -n $1 ]] && [[ $mailSendSucc == true ]] ; then
echo "Process finished, no errors found!" > $mailFile
mail -s "$mailSubjectSucc" $mailTo < $mailFile
fi
if [[ -n $1 ]] && [[ $mailSendFail == true ]] ; then
echo "Process has failed at step: $1" > $mailFile
mail -s "$mailSubjectFail" $mailTo < $mailFile
fi
}
## Checks debug status.
ifDebug() { [[ $debug == true ]] ; }
## Checks lock status.
ifLock() { [[ $lockCheck == true ]] ; }
## Outputs process success.
succ() { msg "%s %s!\n\n" "$(tStamp)" "$(tf "SUCCESS" "bold" "green")" \
; sendMail ; exit 0 ; }
## Outputs process fail.
fail() { msg "%s %s at %s!\n\n" "$(tStamp)" "$(tf "FAIL" "bold" "red")" \
"$(tf "$1" "bold" "underline" "yellow")" ; sendMail "$1" ; exit 1 ; }
## --------- ##
## Functions ##
## --------- ##
## Checks configuration.
checkConf() {
## Check file/directory permissions.
checkPerm() {
if [[ ! -n ${2} ]] ; then
[[ -r ${1} ]] && [[ -w ${1} ]] && echo 1 || echo 0 ;
else
case "$2" in
"f" ) [[ -f ${1} ]] && [[ -r ${1} ]] && [[ -w ${1} ]] && \
echo 1 || echo 0 ;;
"d" ) [[ -d ${1} ]] && [[ -r ${1} ]] && [[ -w ${1} ]] && \
echo 1 || echo 0 ;;
"fd" ) [[ -d ${1} ]] || [[ -f ${1} ]] && [[ -r ${1} ]] && \
[[ -w ${1} ]] && echo 1 || echo 0 ;;
esac
fi
}
## Output file/directory status.
status() { [[ $1 == 1 ]] && tf "OK" "bold" "green" || \
tf "NOT OK" "bold" "red" ; }
## Check source.
pass=$(( pass + $(checkPerm "$src" "fd") ))
ifDebug && msg " -> Source\t\t%s\tis set to: %s\n" \
"$(status "$(checkPerm "$src" "fd")")" "$(tf $src "bold")"
## Check runtime directory.
pass=$(( pass + $(checkPerm "$runDir" "d") ))
ifDebug && msg " -> Runtime directory %s\tis set to: %s\n" \
"$(status "$(checkPerm "$runDir" "d")")" "$(tf $runDir "bold")"
## Check output directory.
pass=$(( pass + $(checkPerm "$outDir" "d") ))
ifDebug && msg " -> Output directory %s\tis set to: %s\n" \
"$(status "$(checkPerm "$outDir" "d")")" "$(tf $outDir "bold")"
## Check archive directory.
pass=$(( pass + $(checkPerm "$archDir" "d") ))
ifDebug && msg " -> Archive directory %s\tis set to: %s\n" \
"$(status "$(checkPerm "$archDir" "d")")" "$(tf $archDir "bold")"
## Display rest of the config.
ifDebug && msg " -> Archive\t\t\tis set to: %s\n" \
"$(tf $archiveFN "bold")"
ifDebug && msg " -> Log file\t\t\tis set to: %s\n" \
"$(tf $logName "bold")"
ifDebug && ifLock && msg " -> Lock file\t\t\tis set to: %s\n" \
"$(tf $lockName "bold")"
ifDebug && msg " -> Timestamp\t\t\tis set to: %s\n" \
"$(tf "$timeStamp" "bold")"
ifDebug && msg " -> Compressor\t\t\tis set to: %s\n" \
"$(tf "$compressor" "bold")"
## Validate config
if [[ $pass == 4 ]] ; then
ifDebug && msg " -> Configuration is %s\n" "$(status 1)"
else
msg " -> Configuration is %s, exiting...\n" "$(status 0)"
fail "configuration check"
fi
}
## Checks for lock file.
checkLock() {
[[ -f ${lockFile} ]] && ifDebug && msg \
" -> Lock file %s, waiting iterations are set to: %s\n" \
"$(tf "is in place" "bold")" "$(tf "$lockWait" "bold")"
for ((i=1; i<=lockWait; i++)) ; do
if [[ -f ${lockFile} ]] ; then
ifDebug && msg " -> waiting for %s (%s)\n" \
"$(tf "$(secToTime "$lockSleep")" "bold")" \
"$(tf "$i" "bold" "yellow")" ; sleep $lockSleep
else
i=1000
fi
if [[ $i == "$lockWait" ]] ; then
msg " -> Lock file %s, exiting...\n" "$(tf "still in place" "bold")"
fail "lock file check"
fi
done
}
## Checks if the old archive exists, if it does, deletes it.
checkForOldArch() {
if [[ -f ${archive} ]] ; then
oldArchCount() {
res=$(printf "%s" "$(ls -afq $archDir | wc -l)")
echo $(( res - 2 ))
}
oldestArch() {
find $archDir -type f -mtime -$oldArchDaysBack -print0 \
| xargs -0 ls -tr | head -n 1
}
## Move previous archive to the vault and rename it.
ifDebug && msg \
" -> Previous archive file %s, created on %s in %s, moving...\n" \
"$(tf "exists" "bold" "yellow")" \
"$(tf "$(date -r $archive +"%Y.%m.%d")" "bold")" \
"$(tf "$(date -r $archive +"%R")" "bold")"
prevArch="$archDir/$archName$(date -r $archive +"_%Y%m%d-%H%M%S")$archExt"
mv -f "$archive" "$prevArch" || fail "moving archive to the vault"
## Check if previous archive were moved to the vault.
if [[ -f ${prevArch} ]] && [[ ! -f ${archive} ]] ; then
ifDebug && msg \
" -> Previous archive %s to the vault as: %s, proceeding...\n" \
"$(tf "moved" "bold" "green")" "$(tf "$prevArch" "bold")"
execute=$(( execute + 1 ))
else
msg " -> %s %s previous archive to the vault, exiting...\n" \
"$(tf "WARNING!" "bold" "yellow")" "$(tf "Can't move" "bold")"
fail "moving archive to the vault"
fi
## Count old archive files inside the vault and delete the oldest.
oldArchCount=$(oldArchCount)
if [[ $oldArchCount -gt $maxOldArch ]] ; then
ifDebug && msg " -> Number of old archives inside the vault is: %s\n" \
"$(tf "$(oldArchCount)" "bold")"
for ((i=oldArchCount; i>maxOldArch; i--)) ; do
oldestArch=$(oldestArch)
rm -f "$oldestArch" || fail "delete oldest archive"
if [[ ! -f ${oldestArch} ]] ; then
ifDebug && msg " -> Oldest file (%s) %s, proceeding...\n" \
"$(tf "$oldestArch" "bold")" "$(tf "was deleted" "bold" "yellow")"
else
msg " -> %s %s the oldest archive (%s), exiting...\n" \
"$(tf "WARNING!" "bold" "yellow")" "$(tf "Can't delete" "bold")" \
"$(tf "$oldestArch" "bold")" ; fail "delete oldest archive"
fi
done
fi
## Check if old archives were indeed deleted.
ifDebug && msg " -> Number of old archives inside the vault is: %s\n" \
"$(tf "$(oldArchCount)" "bold")"
oldArchCount=$(oldArchCount)
if [[ $oldArchCount -gt 10 ]] ; then
msg " -> %s %s the oldest archive(s), exiting...\n" \
"$(tf "WARNING!" "bold" "yellow")" "$(tf "Can't delete" "bold")"
fail "delete oldest archive(s)"
else
execute=$(( execute + 1 ))
fi
else
ifDebug && msg " -> Old archive %s, proceeding...\n" \
"$(tf "does not exist" "bold" "green")" ; execute=2
fi
}
## Executes compression.
execComp() {
## Go to source directory.
cd $srcDir || fail "cd to source directory"
if [[ ${PWD} != "$srcDir" ]] ; then
msg " -> %s Can't cd to source directory, exiting...\n%s" \
"$(tf "WARNING!" "bold" "yellow")" ; fail "cd to source directory"
fi
execTime=$( { time tar cf - $srcName | $compressor - > $archive ; } 2>&1 )
}
## Gets object size values.
size() {
[[ $2 == "b" ]] && du -bs "$1" | awk '{ print $1 }'
[[ $2 == "h" ]] && du -hs "$1" | awk '{ print $1 }'
}
## Rounds floating numbers.
round() { printf %."$2"f "$(echo "(((10^$2)*$1)+0.5)/(10^$2)" | bc)" ; }
## Gets compression ratio.
compRatio() { printf "%.*f" 2 "$(let res="$1/$2"; printf "%s" "$res")" ; }
## Outputs compression info.
compInf() {
msg "\t-> Source size: %s (%s bytes)\n" \
"$(tf "$(size "$1" "h")" "bold")" "$(tf "$(size "$1" "b")" "bold")"
msg "\t-> Archive size: %s (%s bytes)\n" \
"$(tf "$(size "$2" "h")" "bold")" "$(tf "$(size "$2" "b")" "bold")"
msg "\t-> Compression ratio: %s\n" \
"$(tf "$(compRatio "$(size "$1" "b")" "$(size "$2" "b")")" "bold")"
}
## Begins compression process.
compress() {
if [[ $execute == 2 ]] ; then
ifDebug && msg " -> Flag %s set, executing...\n" "$(tf "is" "bold" "green")"
execComp
execTime=$(round "$execTime" 0)
execTime=$(secToTime "$execTime")
## Check if archive file created.
if [[ -f ${archive} ]] ; then
msg " -> Archive %s created in %s!\n" "$(tf $archive "bold")" \
"$(tf "$execTime" "bold")" ; compInf $src $archive ; succ
else
msg " -> %s Archive file was %s created, exiting...\n" \
"$(tf "WARNING!" "bold" "yellow")" "$(tf "not" "bold" "red")"
fail "archive file creation"
fi
else
msg " -> Flag %s set, exiting...\n" "$(tf "is not" "bold" "red")"
fail "execution flag check"
fi
}
## ---------- ##
## Initialize ##
## ---------- ##
msg "%s Initializing...\n" "$(tStamp)"
checkConf ## Check configuration.
ifLock && checkLock ## Check for lock file.
checkForOldArch ## Check for old archive file.
compress ## Begin compression.