sync.sh 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. #!/bin/bash
  2. # Config
  3. BASE_LOCAL="`~/bin/video/mediaPath`"
  4. BASE_REMOTE="/Volumes/Bitcasa Infinite Drive"
  5. # Command-line arguments
  6. SUB_DIR="${1}"
  7. declare -i NUM_FILES
  8. NUM_FILES=1
  9. if [ -n "${2}" ]; then
  10. NUM_FILES="${2}"
  11. fi
  12. declare -i DELAY_DAYS
  13. DELAY_DAYS=30
  14. if [ -n "${3}" ]; then
  15. DELAY_DAYS="${3}"
  16. fi
  17. # Usage checks
  18. if [ -z "${SUB_DIR}" ] || [ $NUM_FILES -lt 1 ] || [ $DELAY_DAYS -lt 1 ]; then
  19. echo "Usage: `basename "${0}"` sub_directory [num_files] [delay_days]" 1>&2
  20. exit 1
  21. fi
  22. # Allow usage with absolute local paths
  23. if [ "`echo "${SUB_DIR}" | head -c 1`" == '/' ]; then
  24. SUB_DIR="`echo "${SUB_DIR}" | sed 's%^'"${BASE_LOCAL}"'/%%'`"
  25. fi
  26. # Sanity checks
  27. if [ ! -d "${BASE_LOCAL}/${SUB_DIR}" ]; then
  28. echo "Invalid local directory: ${BASE_LOCAL}/${SUB_DIR}" 1>&2
  29. exit 1
  30. fi
  31. if [ ! -d "${BASE_REMOTE}" ]; then
  32. echo "Bitcasa drive not mounted" 1>&2
  33. exit 1
  34. fi
  35. # Ensure the subdirectory exists on the remote drive
  36. if [ ! -d "${BASE_REMOTE}/${SUB_DIR}" ]; then
  37. mkdir -p "${BASE_REMOTE}/${SUB_DIR}"
  38. fi
  39. # Grab and sort the local file list
  40. # Limit files by mtime, but include all directories
  41. TMP_LOCAL="`mktemp -t sync.local.XXXXXXXX`"
  42. TMP_LOCAL2="`mktemp -t sync.local2.XXXXXXXX`"
  43. (cd "${BASE_LOCAL}" && find "${SUB_DIR}" -type f -mtime "+${DELAY_DAYS}d" > "${TMP_LOCAL2}")
  44. (cd "${BASE_LOCAL}" && find "${SUB_DIR}" -type d >> "${TMP_LOCAL2}")
  45. cat "${TMP_LOCAL2}" | sort > "${TMP_LOCAL}"
  46. # Grab and sort the remote file list
  47. TMP_REMOTE="`mktemp -t sync.remote.XXXXXXXX`"
  48. (cd "${BASE_REMOTE}" && find "${SUB_DIR}" | sort > "${TMP_REMOTE}")
  49. # Diff to find the first mis-matched file, then drop out temp files
  50. TMP_DIFF="`mktemp -t sync.diff.XXXXXXXX`"
  51. TMP_DIFF2="`mktemp -t sync.diff2.XXXXXXXX`"
  52. diff -u "${TMP_LOCAL}" "${TMP_REMOTE}" | grep "^[\+\-]${SUB_DIR}" > "${TMP_DIFF2}"
  53. rm -f "${TMP_LOCAL}" "${TMP_LOCAL2}" "${TMP_REMOTE}"
  54. # Filter junk
  55. grep -v '\/\._' "${TMP_DIFF2}" | grep -v '\/\.DS_Store$' > "${TMP_DIFF}"
  56. rm -f "${TMP_DIFF2}"
  57. # Limit NUM_FILES to the number of files available
  58. COUNT="`cat "${TMP_DIFF}" | wc -l`"
  59. if [ $NUM_FILES -gt $COUNT ]; then
  60. NUM_FILES=$COUNT
  61. fi
  62. # Loop for NUM_FILES
  63. for (( i=1; i<=${NUM_FILES}; i++ )); do
  64. # Choose the file/directory to sync
  65. FILE="`head -n $i "${TMP_DIFF}" | tail -n 1`"
  66. ACTION="`echo "${FILE}" | head -c 1`"
  67. FILE="`echo "${FILE}" | cut -d "${ACTION}" -f 2-`"
  68. # Construct absolute paths
  69. PATH_LOCAL="${BASE_LOCAL}/${FILE}"
  70. PATH_REMOTE="${BASE_REMOTE}/${FILE}"
  71. # Determine the action (i.e. copy to or delete from remote)
  72. if [ "${ACTION}" == '+' ]; then
  73. echo "Will not delete from remote: ${FILE}" 1>&2
  74. exit 2
  75. elif [ "${ACTION}" == '-' ]; then
  76. # Handle files by type
  77. if [ -h "${PATH_LOCAL}" ]; then
  78. echo "Unable to create symlink: ${FILE}" 1>&2
  79. exit 2
  80. elif [ -d "${PATH_LOCAL}" ]; then
  81. echo "Creating directory: ${FILE}"
  82. mkdir "${PATH_REMOTE}"
  83. elif [ -f "${PATH_LOCAL}" ] && [ -r "${PATH_LOCAL}" ]; then
  84. echo "Copying: ${FILE}"
  85. cp "${BASE_LOCAL}/${FILE}" "${BASE_REMOTE}/${FILE}"
  86. else
  87. echo "Unable to copy file: ${FILE}" 1>&2
  88. exit 2
  89. fi
  90. else
  91. echo "Invalid action: ${ACTION}" 1>&2
  92. exit 2
  93. fi
  94. done
  95. # Cleanup
  96. rm -f "${TMP_DIFF}"
  97. exit 0