{"id":50528253,"url":"https://github.com/earentir/fndupe","last_synced_at":"2026-06-03T10:02:09.938Z","repository":{"id":352210976,"uuid":"1213591022","full_name":"earentir/fndupe","owner":"earentir","description":null,"archived":false,"fork":false,"pushed_at":"2026-04-18T11:40:57.000Z","size":21,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-18T13:25:25.691Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/earentir.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-17T14:43:54.000Z","updated_at":"2026-04-18T11:41:01.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/earentir/fndupe","commit_stats":null,"previous_names":["earentir/fndupe"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/earentir/fndupe","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earentir%2Ffndupe","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earentir%2Ffndupe/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earentir%2Ffndupe/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earentir%2Ffndupe/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/earentir","download_url":"https://codeload.github.com/earentir/fndupe/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/earentir%2Ffndupe/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33858578,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-03T02:00:06.370Z","response_time":59,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-03T10:02:09.141Z","updated_at":"2026-06-03T10:02:09.916Z","avatar_url":"https://github.com/earentir.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fndupe\n\n`fndupe` walks a directory tree and reports files whose names are **identical** or **fuzzily similar**. It compares names within the same extension by default (so sidecars like `.nfo` are not lumped with `.mkv` unless you opt in). Optional **content hashing** can require byte-identical files inside each name-based group.\n\nBuilt with Go 1.26+. From the repository root:\n\n```bash\ngo build -o fndupe .\n./fndupe --help\ngo test ./...\n```\n\nAll examples below assume your current working directory is the **repository root**, so paths like `testdata/namefixtures/...` resolve correctly. That tree is small, deterministic, and meant for trying every mode.\n\n---\n\n## Examples\n\nThe `testdata/namefixtures` layout:\n\n| Subtree | Purpose |\n| --- | --- |\n| `similar/` | Fuzzy near-duplicate names (same extension) |\n| `exact/` | Same basename in different folders (good for `--exact`) |\n| `common-ext/{image,video,audio,doc,code,arch}/` | One scenario per `--common-ext` preset |\n| `exclude/` | Files useful for `--exclude-ext` / `--exclude-str` |\n| `mixed/` | Odd names (case, dots, no extension, hidden) |\n\n### Meta (no scan)\n\n```bash\nfndupe -h\nfndupe --help\nfndupe -v\nfndupe --version\n```\n\n### Scan root\n\n```bash\nfndupe\nfndupe .\nfndupe testdata/namefixtures\n```\n\n### Similarity threshold (`-t` / `--threshold`)\n\n```bash\nfndupe -t 0.7 testdata/namefixtures/similar\nfndupe --threshold 0.9 testdata/namefixtures/similar\n```\n\n### Exact filename match (no fuzzy scoring)\n\n```bash\nfndupe --exact testdata/namefixtures/exact\n```\n\n### Similarity metric (`--metric`)\n\n```bash\nfndupe --metric hybrid testdata/namefixtures/similar\nfndupe --metric levenshtein testdata/namefixtures/similar\nfndupe --metric jaccard testdata/namefixtures/similar\nfndupe --metric dice testdata/namefixtures/similar\n```\n\n### Skip extensions during scan (`--exclude-ext`)\n\nComma-separated list (no leading dots required):\n\n```bash\nfndupe --exclude-ext nfo,srt testdata/namefixtures/exclude\n```\n\nBare flag: do **not** filter extensions, but allow **fuzzy matching across different extensions** (legacy behavior):\n\n```bash\nfndupe --exclude-ext testdata/namefixtures\n```\n\n### Skip filenames containing substrings (`--exclude-str`)\n\n```bash\nfndupe --exclude-str sample testdata/namefixtures/exclude\nfndupe --exclude-str sample,srt testdata/namefixtures/exclude\n```\n\n### Compare basename only for selected types (`--common-ext`)\n\n**Preset** (built-in extension sets — see `--help` for the full lists):\n\n```bash\nfndupe --common-ext image testdata/namefixtures/common-ext/image\nfndupe --common-ext video testdata/namefixtures/common-ext/video\nfndupe --common-ext audio testdata/namefixtures/common-ext/audio\nfndupe --common-ext doc testdata/namefixtures/common-ext/doc\nfndupe --common-ext code testdata/namefixtures/common-ext/code\nfndupe --common-ext arch testdata/namefixtures/common-ext/arch\n```\n\n**Custom extension list**:\n\n```bash\nfndupe --common-ext jpg,png,bmp testdata/namefixtures/common-ext/image\n```\n\n**Union of every preset** (bare `--common-ext`):\n\n```bash\nfndupe testdata/namefixtures --common-ext\n```\n\nIf the next token after `--common-ext` would be parsed as the preset value, put the directory first (as above) or use `=`:\n\n```bash\nfndupe --common-ext=video testdata/namefixtures/common-ext/video\n```\n\n### Content verification after name matching (`--hash`)\n\nStreaming hash; default algorithm is **xxh64** when `--hash` is used without a value.\n\n`--hash` does **not** require `--exact`. Without `--exact`, name groups come from **fuzzy** matching first; the hash step then drops files that do not share identical contents. If fuzzy matching finds no groups, nothing is hashed (there is no separate “hash-only” pass).\n\n```bash\nfndupe --hash --exact testdata/namefixtures/exact\nfndupe --hash testdata/namefixtures/exact\nfndupe --hash --no-progress testdata/namefixtures\nfndupe --hash xxh64 --exact testdata/namefixtures/exact\nfndupe --hash xxhash --exact testdata/namefixtures/exact\nfndupe --hash sha256 --exact testdata/namefixtures/exact\nfndupe --hash=xxh64 --exact testdata/namefixtures/exact\n```\n\n### Progress and color\n\n```bash\nfndupe --no-progress testdata/namefixtures\nfndupe --no-color testdata/namefixtures/similar\nfndupe --no-colour testdata/namefixtures/similar\n```\n\nColor is also off when `NO_COLOR` is set in the environment (non-empty).\n\n### Combined runs (realistic)\n\n```bash\nfndupe --exact --hash --no-progress testdata/namefixtures/exact\nfndupe --common-ext doc -t 0.75 --metric levenshtein testdata/namefixtures/common-ext/doc\nfndupe --exclude-ext nfo --exclude-str sample --no-progress testdata/namefixtures/exclude\n```\n\n### Flag order pitfall\n\nString flags (`--metric`, `--exclude-ext`, `--exclude-str`, `--common-ext`, `--hash`) must not receive your scan path by mistake. Wrong:\n\n```bash\n# BAD: /path is parsed as --common-ext value, not the scan root\nfndupe --common-ext testdata/namefixtures/common-ext/video\n```\n\nRight:\n\n```bash\nfndupe testdata/namefixtures/common-ext/video --common-ext video\nfndupe --common-ext=video testdata/namefixtures/common-ext/video\n```\n\nIf a flag value looks like a filesystem path, `fndupe` exits with an error explaining to use `flag=value` or put `[dir]` last.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearentir%2Ffndupe","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fearentir%2Ffndupe","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fearentir%2Ffndupe/lists"}