Guest User

Untitled

a guest
Oct 17th, 2019
132
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.23 KB | None | 0 0
  1. #!/bin/bash
  2.  
  3.  
  4. trim_string() {
  5. : "${1#"${1%%[![:space:]]*}"}"
  6. : "${_%"${_##*[![:space:]]}"}"
  7. printf '%s\n' "$_"
  8. }
  9. pathOrCmd() {
  10. if [[ "$*" =~ ^[[:blank:]]*\[(.+)\].*$ ]]; then
  11. echo $(eval "${BASH_REMATCH[1]}" | xargs)
  12. else
  13. echo "$*"
  14. fi
  15. }
  16. chownSudo() {
  17. if [ -n "$SUDO_USER" ]; then
  18. chown "${SUDO_USER}:${SUDO_USER}" "$*"
  19. fi
  20. }
  21. expandGlobs() {
  22. shopt -s nullglob
  23. eval printf "\"%s\n\"" "$*"
  24. shopt -u nullglob
  25. }
  26. printCSI() {
  27. csi="$1"
  28. shift
  29. printf "\e[${csi}%s\e[0m" "$*"
  30. }
  31. printRed() { printCSI '91m' "$*"; }
  32. printYellow() { printCSI '93m' "$*"; }
  33. printGreen() { printCSI '92m' "$*"; }
  34. printMagenta() { printCSI '95m' "$*"; }
  35. printDetail() {
  36. printGreen "$1"
  37. shift
  38. echo " $*"
  39. }
  40. printWarning() { printYellow "$*"; echo ""; }
  41. printError() { printError "$*"; echo ""; }
  42. printEv() {
  43. eval printf '"%s"' "\${$1+$1}\ ";
  44. }
  45.  
  46.  
  47. exampleProfileText="BackupName #first line, mandatory, bash-evaluated
  48. BackupSourceDir #optional (default is current dir), bash-evaluated
  49. Flags #optional
  50. # t - add timestamp
  51. # e - elevate with sudo and chmod with current user
  52. # s - follow symlinks
  53. # i - incremental [HARD-CODED-DISABLED]
  54.  
  55. # optional blank lines
  56. # if you didn't noticed yet, this is a comment
  57.  
  58. #include paths
  59. .config/program #literal path
  60. [find . -type f -iname '*.txt'] #command output (always automatically xarg-ed)
  61.  
  62. # blank lines
  63.  
  64. #optional exclude paths
  65. ./config/*.txt #path with wildcards (tar default behavior)
  66. [echo '.*'] #command output (always automatically xarg-ed)
  67. "
  68.  
  69.  
  70. # PARSE ARGS
  71. action="gen"
  72. dryrun=0
  73. modes=('' 1 '' '')
  74. POSITIONAL=()
  75. while [[ $# -gt 0 ]]; do
  76. key="$1"
  77. case "$key" in
  78. -h|--help)
  79. cat << EOF
  80. Backup generator script v1 - Microeinstein
  81. Generate backups by pre-made profiles
  82.  
  83. Usage: $0 [options] [PROFILE]
  84.  
  85. Options:
  86. -h --help Show this help message.
  87. -d --dry-run Do not execute the final command.
  88. -r --remove Remove any backup of this profile.
  89. -e --example Dump the example in "./example.profile"
  90. (ignores dry-run mode)
  91.  
  92. +s -+symlinks (Force-mode) Follow symlinks.
  93. +t -+timestamp (Force-mode) Add current timestamp.
  94.  
  95. Profile:
  96. A filename, otherwise <stdin> will be used.
  97.  
  98.  
  99. example.profile:
  100. ----------------
  101. $exampleProfileText
  102. EOF
  103. exit 0
  104. ;;
  105. -e|--example)
  106. echo "$exampleProfileText" > example.profile
  107. if [ $? = 0 ]; then
  108. echo "Example dumped."
  109. else
  110. echo "Cannot dump example, sorry."
  111. fi
  112. exit 0
  113. ;;
  114. -d|--dry-run)
  115. printWarning "[DryRun]"
  116. dryrun=1
  117. ;;
  118. -r|--remove)
  119. printWarning "[Remove]"
  120. action="rem"
  121. ;;
  122. # +i) modes[0]=1 ;;
  123. +s|-+symlinks) modes[1]= ;;
  124. +t|-+timestamp) modes[2]=1 ;;
  125. *)
  126. POSITIONAL+=("$1")
  127. ;;
  128. esac
  129. shift
  130. done
  131. set -- "${POSITIONAL[@]}"
  132.  
  133.  
  134. # PARSE PROFILE
  135. if [[ $# -eq 0 ]]; then
  136. echo "Reading from stdin..."
  137. fi
  138. initialDir="$PWD"
  139. parsepart=0
  140. name="unknown"
  141. dir="."
  142. include=""
  143. exclude=""
  144. while read -r line; do
  145. parseModes() {
  146. # if [[ "$1" == *i* ]]; then modes[0]=1; fi
  147. if [[ "$1" == *s* ]]; then modes[1]=; fi
  148. if [[ "$1" == *t* ]]; then modes[2]=1; fi
  149. if [[ "$1" == *e* ]]; then modes[3]=1; fi
  150. printDetail "Modes:" $({ \
  151. printf '%s ' "${modes[0]:+incremental}"; \
  152. printf '%s ' "${modes[1]:+keepSymlinks}"; \
  153. printf '%s ' "${modes[2]:+addTimestamp}"; \
  154. printf '%s ' "${modes[3]:+elevated}"; \
  155. } | xargs)
  156. }
  157. line=$(trim_string "$line")
  158. line=$(sed 's/#.*$//g' <<< "$line")
  159. case $parsepart in
  160. 0)
  161. name=$(eval echo "$line")
  162. printDetail "Name:" "$name"
  163. ((parsepart++))
  164. ;;
  165. 1)
  166. line=$(eval echo "$line")
  167. if [ -z "$line" ]; then
  168. printWarning "Using default directory... (unspecified)"
  169. printDetail "Directory:" "$dir"
  170. parsepart=3
  171. elif [ -d "$line" ]; then
  172. dir="$line"
  173. pushd "$line" >/dev/null 2>&1
  174. printDetail "Directory:" "$dir"
  175. ((parsepart++))
  176. else
  177. printWarning "Using default directory... (not a directory)"
  178. printDetail "Directory:" "$dir"
  179. parseModes "$line"
  180. parsepart=3
  181. fi
  182. ;;
  183. 2)
  184. parseModes "$line"
  185. ((parsepart++))
  186. ;;
  187. 3)
  188. if [[ $action == rem ]]; then
  189. parsepart=99
  190. fi
  191. if [ -z "$line" ]; then
  192. if [ -n "$include" ]; then
  193. ((parsepart++))
  194. fi
  195. else
  196. line=$(pathOrCmd "$line")
  197. include="${include} $line"
  198. printDetail "Include:" "$line"
  199. fi
  200. ;;
  201. 4)
  202. if [ -z "$line" ]; then
  203. if [ -n "$include" ]; then
  204. ((parsepart++))
  205. fi
  206. else
  207. line=$(pathOrCmd "$line")
  208. exclude="${include} $line"
  209. printDetail "Exclude:" "$line"
  210. fi
  211. ;;
  212. esac
  213. done < "${1:-/dev/stdin}"
  214. popd >/dev/null 2>&1
  215.  
  216. echo ""
  217. case "$action" in
  218. gen)
  219. bkpIn=$(realpath ./backupInclude.txt)
  220. bkpEx=$(realpath ./backupExclude.txt)
  221. eval printf '"%s\n"' "$include" > "$bkpIn"
  222. eval printf '"%s\n"' "$exclude" > "$bkpEx"
  223. chownSudo "$bkpIn"
  224. chownSudo "$bkpEx"
  225. outFile="$name"
  226. if [ -n "${modes[0]}" ]; then
  227. lastIncr=$(find . -type f -iname "${name}_*.tgz" | sort -V | tail -n-1)
  228. num=1
  229. if [[ "$lastIncr" =~ _([[:digit:]]+) ]]; then
  230. num="${BASH_REMATCH[1]}"
  231. ((num++))
  232. fi
  233. outFile="${outFile}_${num}"
  234. fi
  235. if [ -n "${modes[2]}" ]; then
  236. ts=$(date -Iseconds | sed 's/T/_/g' | head -c-7 | xargs)
  237. outFile="${outFile}_${ts}"
  238. fi
  239. outFile=$(realpath "./$outFile.tgz")
  240. incrFile=$(realpath "./$name.gbkp")
  241. pushd "$dir" >/dev/null 2>&1
  242. args=(
  243. $(eval echo "\${modes[0]:+--listed-incremental='$incrFile'}")
  244. ${modes[1]:+--keep-directory-symlink}
  245. --exclude-from="\"$bkpEx\""
  246. --files-from="\"$bkpIn\""
  247. -f "\"$outFile\""
  248. )
  249. cmd="tar -czv ${args[@]}"
  250. ;;
  251. rem)
  252. arg=$(eval echo "${name}* backup{In,Ex}clude.txt")
  253. cmd="rm -f $arg"
  254. ;;
  255. esac
  256. if [ -n "${modes[3]}" ]; then
  257. cmd="sudo bash -c '${cmd} && chown \"${USER}:${USER}\" \"$outFile\"'"
  258. fi
  259. printMagenta "$cmd"; echo ""
  260. if [ $dryrun = 1 ]; then exit 0; fi
  261. printWarning "Executing..."
  262. eval "$cmd"
  263. err=$?
  264. if [ $err != 0 ]; then
  265. printError "Exit code: $err"
  266. exit $err
  267. fi
  268. if [ $action = gen ]; then
  269. chownSudo "$outFile"
  270. fi
  271. printWarning "Done."
Advertisement
Add Comment
Please, Sign In to add comment