-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathddiff
More file actions
executable file
·112 lines (101 loc) · 3.41 KB
/
Copy pathddiff
File metadata and controls
executable file
·112 lines (101 loc) · 3.41 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
#!/usr/bin/env bash
# Directory/file-wise diff. Compares file/folder names. Does not compare file contents.
#
# author: andreasl
script_name="${0##*/}"
IFS= read -r -d '' script_description <<HELP_EOF
${script_name}
Compare file trees in a readable format using find, sort, comm and sed.
Only compares file/folder names, not contents!
Usage:
${script_name} [OPTIONS] <dir1> <dir2>
${script_name} <dir1> <dir2> [OPTIONS]
Options:
-1, --in-1: Only show entries that are in dir1.
-2, --in-2: Only show entries that are in dir2.
-C, --no-color: Disable colored output.
-d, --only-different: Show only directories/files that exist only in dir1 or only in dir2.
-e <pattern>, --exclude <pattern>: Exclude glob pattern <pattern>, e.g. "*.git".
-h, --help: Print the help message.
-s --only-same: Show only directories/files that exist in both dir1 and dir2.
Same as -1 -2.
Examples:
${script_name} -e "*.git" -C -d dev dev_backup
${script_name} ~/Photos ~/Media -s
${script_name} --help
HELP_EOF
# parse command line arguments
excludes=()
must_be_in_1=false
must_be_in_2=false
only_different=false
only_same=false
source_dir=.
target_dir=.
use_colors=true
while [ "$#" -gt 0 ]; do
case "$1" in
-1 | --in-1)
must_be_in_1=true
;;
-2 | --in-2)
must_be_in_2=true
;;
-C | --no-color)
use_colors=false
;;
-d | --only-different)
only_different=true
;;
-e | --exclude)
excludes+=(-path "$2" -prune -o)
shift
;;
-h | --help)
printf -- "$script_description"
exit 0
;;
-s | --only-same)
only_same=true
;;
*) # unknown option
source_dir="$1"
shift
target_dir="$1"
;;
esac
shift
done
# get the file trees and do the comparisons
# `cd` into the dir and strip the leading `./` instead of using `-printf "%P\n"`, which is GNU-only
tree1="$(cd "$source_dir" && find . "${excludes[@]}" -print | sed -e 's|^\./||' -e 's|^\.$||' | sort)"
tree2="$(cd "$target_dir" && find . "${excludes[@]}" -print | sed -e 's|^\./||' -e 's|^\.$||' | sort)"
output="$(comm <(printf '%s\n' "$tree1") <(printf '%s\n' "$tree2"))"
# postprocess the output from comm, which marks its three columns by leading tabs
# `$'\t'` is a real tab character; writing `\t` in the regex instead would only work with GNU
# sed, as BSD/macOS sed reads it as a literal `t`.
tab=$'\t'
output="$(sed -E "s:(^[^${tab}].*):1 \1:g" <<<"$output")"
output="$(sed -E "s:^${tab}{2}(.*):3 \1:g" <<<"$output")"
output="$(sed -E "s:^${tab}{1}(.*):2 \1:g" <<<"$output")"
# filter the output
if [ "$must_be_in_1" == true ] || [ "$only_same" == true ]; then
output="$(sed '/^2 /d' <<<"$output")"
fi
if [ "$must_be_in_2" == true ] || [ "$only_same" == true ]; then
output="$(sed '/^1 /d' <<<"$output")"
fi
if [ "$only_different" == true ]; then
output="$(sed '/^3 /d' <<<"$output")"
fi
# colorize output
if [ "$use_colors" == true ]; then
red='\\e[31m'
green='\\e[32m'
orange='\\e[33;1m'
nc='\\e[0m'
output="$(sed -E "s:^1 (.*):${red}1 \1${nc}:g" <<<"$output")"
output="$(sed -E "s:^2 (.*):${green}2 \1${nc}:g" <<<"$output")"
output="$(sed -E "s:^3 (.*):${orange}3 \1${nc}:g" <<<"$output")"
fi
printf '%b\n' "$output"