#autoload find_dupes() { local maxdepth=3 regex='.*' ignore_case=false local tmpfile grep_flags="-E" # ---------------------------- # Parse args (all long opts must start with --) # ---------------------------- while [[ $# -gt 0 ]]; do case "$1" in --maxdepth|-d) maxdepth="$2" shift 2 ;; --regex|-r) regex="$2" shift 2 ;; --ignore-case|-i) ignore_case=true shift ;; --) shift break ;; *) echo "find_dupes: unknown option '$1'" >&2 return 1 ;; esac done # grep flags $ignore_case && grep_flags="$grep_flags -i" tmpfile=$(mktemp /tmp/find_dupes.XXXXXX) # ---------------------------- # Scan files # ---------------------------- find . -type f -maxdepth "$maxdepth" ! -path '*/.git/*' \ \( -name "*.zsh" -o -name "*.sh" -o -name "*.zlogin" -o -name "*.symlink" -o ! -name "*.*" \) \ -print0 | while IFS= read -r -d '' file; do grep $grep_flags "$regex" "$file" 2>/dev/null | \ awk ' { gsub(/\r/, "", $0) gsub(/\302\240/, "", $0) line = $0 } /^[[:space:]]*#/ { next } { sub(/^[[:space:]]+/, "", line) sub(/[[:space:]]+$/, "", line) if (length(line) == 0) next if (length(line) < 5) next print line "\t" FILENAME } ' FILENAME="$file" >> "$tmpfile" done # ---------------------------- # Show duplicates # ---------------------------- sort "$tmpfile" | awk -F'\t' ' { line=$1; file=$2 count[line]++ files[line]=files[line] file "\n" } END { for (l in count) if (count[l] > 1) { print "==== Duplicate line: \"" l "\" ====" printf "%s", files[l] print "" } } ' rm -f "$tmpfile" }