{"id":26468764,"url":"https://github.com/olson-sean-k/nym","last_synced_at":"2025-03-19T16:57:40.024Z","repository":{"id":39755538,"uuid":"304547200","full_name":"olson-sean-k/nym","owner":"olson-sean-k","description":"Manipulate files en masse using patterns.","archived":false,"fork":false,"pushed_at":"2023-03-20T07:59:10.000Z","size":182,"stargazers_count":32,"open_issues_count":6,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-18T23:45:34.805Z","etag":null,"topics":["capture-text","cli","filesystem","glob","pattern","rust","wildcard-matches"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/olson-sean-k.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2020-10-16T07:05:58.000Z","updated_at":"2024-08-21T14:26:20.000Z","dependencies_parsed_at":"2023-02-10T01:30:45.093Z","dependency_job_id":null,"html_url":"https://github.com/olson-sean-k/nym","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fnym","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fnym/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fnym/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/olson-sean-k%2Fnym/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/olson-sean-k","download_url":"https://codeload.github.com/olson-sean-k/nym/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244470242,"owners_count":20457906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["capture-text","cli","filesystem","glob","pattern","rust","wildcard-matches"],"created_at":"2025-03-19T16:57:39.448Z","updated_at":"2025-03-19T16:57:40.018Z","avatar_url":"https://github.com/olson-sean-k.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n    \u003cimg alt=\"Nym\" src=\"https://raw.githubusercontent.com/olson-sean-k/nym/master/doc/nym.svg?sanitize=true\" width=\"320\"/\u003e\n\u003c/div\u003e\n\u003cbr/\u003e\n\n**Nym** is a cross-platform library and command line interface for manipulating\nfiles using patterns. It is inspired by and very loosely based upon `mmv`.\n\n[![GitHub](https://img.shields.io/badge/GitHub-olson--sean--k/nym-8da0cb?logo=github\u0026style=for-the-badge)](https://github.com/olson-sean-k/nym)\n[![docs.rs](https://img.shields.io/badge/docs.rs-nym-66c2a5?logo=rust\u0026style=for-the-badge)](https://docs.rs/nym)\n[![crates.io](https://img.shields.io/crates/v/nym.svg?logo=rust\u0026style=for-the-badge)](https://crates.io/crates/nym)\n\n## Usage\n\nNym commands are formed from flags, options, and patterns. Most commands are\ntransforms composed of both a from-pattern to match source files and a\nto-pattern to resolve destination paths. Transforms include the `append`,\n`copy`, `link` and `move` commands. Some commands, such as `find`, use only a\nfrom-pattern.\n\nCommands that write to the file system (i.e., transforms like `copy`) are\ninteractive by default and print a manifest and then prompt to continue before\nwriting. This behavior can be controlled with the `--interactive` option.\n\nNym operates exclusively on files (with the exception of the `--parent`/`-p`\nflag, which creates parent directories in destination paths derived from\nto-patterns). Commands never apply to directories. It is **not** possible to\ncopy, link, or move directories, for example.\n\nThe following command copies all files in the working directory tree to a\nneighboring file with an appended `.bak` extension.\n\n```shell\nnym copy '**' '{#0}.bak'\n```\n\nHere, `copy` is the sub-command (also known as an actuator), `**` is the\nfrom-pattern, and `{#0}.bak` is the to-pattern. Note that in most shells\npatterns must be escaped to avoid interacting with shell features like\nexpansion. Quoting patterns usually prevents these unwanted interactions.\n\nThe following command finds all files beneath a `src` directory with either the\n`.go` or `.rs` extension.\n\n```shell\nnym find '**/src/**/*.{go,rs}'\n```\n\n## From-Patterns\n\nFrom-patterns match source files to actuate using Unix-like globs. These globs\nresemble literal paths, but additionally support wildcards, character classes,\nand alternatives that can be matched against paths on the file system. Matches\nprovide capture text that can be used in to-patterns.\n\nGlobs are opinionated about path separators. Forward slash `/` is **always** the\npath separator and back slashes `\\` are forbidden (back slash is used for escape\nsequences, but the literal sequence `\\\\` is not supported). Separators are\nnormalized across platforms; glob patterns can match paths on Windows, for\nexample.\n\n### Wildcards\n\nWildcards match some amount of arbitrary text in paths and are the most\nfundamental tool provided by globs.\n\nThe tree wildcard `**` matches zero or more sub-directories. **This is the only\nway to match against arbitrary directories**; all other wildcards do **not**\nmatch across directory boundaries. When a tree wildcard participates in a match\nand does not terminate the pattern, its capture includes a trailing path\nseparator. If a tree wildcard does not participate in a match, its capture is an\nempty string with no path separator. Tree wildcards must be delimited by path\nseparators or a termination (such as the beginning and/or end of a glob or\nsub-glob). Tree wildcards cannot be adjacent to other tree wildcards. If a glob\nconsists solely of a tree wildcard, then it matches all files in the working\ndirectory tree.\n\nThe zero-or-more wildcards `*` and `$` match zero or more of any character\n**except path separators**. Zero-or-more wildcards cannot be adjacent to other\nzero-or-more wildcards. The `*` wildcard is eager and will match the longest\npossible text while the `$` wildcard is lazy and will match the shortest\npossible text. When followed by a literal, `*` stops at the last occurrence of\nthat literal while `$` stops at the first occurence.\n\nThe exactly-one wildcard `?` matches any single character **except path\nseparators**. Exactly-one wildcards do not group automatically, so a pattern of\ncontiguous wildcards such as `???` form distinct captures for each `?` wildcard.\nAn alternative can be used to group exactly-one wildcards into a single capture,\nsuch as `{???}` (see below).\n\n### Character Classes\n\nCharacter classes match any single character from a group of literals and ranges\n**except path separators**. Classes are delimited by square brackets `[...]`.\nIndividual character literals are specified as is, such as `[ab]` to match\neither `a` or `b`. Character ranges are formed from two characters separated by\na hyphen, such as `[x-z]` to match `x`, `y`, or `z`.\n\nAny number of character literals and ranges can be used within a single\ncharacter class. For example, `[qa-cX-Z]` matches any of `q`, `a`, `b`, `c`,\n`X`, `Y`, or `Z`.\n\nCharacter classes may be negated by including an exclamation mark `!` at the\nbeginning of the class pattern. For example, `[!a]` matches any character except\nfor `a`.\n\nNote that character classes can also be used to escape metacharacters like `*`,\n`$`, etc., though globs also support escaping via a backslash `\\`. To match the\ncontrol characters `[`, `]`, and `-` within a character class, they must be\nescaped via a backslash, such as `[a\\-]` to match `a` or `-`.\n\n### Alternatives\n\nAlternatives match an arbitrary sequence of comma separated sub-globs delimited\nby curly braces `{...,...}`. For example, `{a?c,x?z,foo}` matches any of the\nsub-globs `a?c`, `x?z`, or `foo` in order. Alternatives may be arbitrarily\nnested, such as in `{a,{b,{c,d}}}`.\n\nAlternatives form a single capture group regardless of the contents of their\nsub-globs. This capture is formed from the complete match of the sub-glob, so if\nthe sub-glob `a?c` matches `abc` in `{a?c,x?z}`, then the capture text will be\n`abc` (**not** `b` as it would be outside of an alternative sequence).\nAlternatives can be used to group capture text using a single sub-glob, such as\n`{*.{go,rs}}` to capture an entire file name with a particular extension or\n`{??}` to group a sequence of exactly-one wildcards.\n\nSub-globs, especially those with path boundaries, must consider neighboring\npatterns and have limitations. For example, wildcards and path separators\ngenerally cannot be adjacent, so `a{b,c/**}` and `a{/b,/c}` are allowed but\n`a{b,**/c}` and `a/{/b,c}` are not. Additionally, singular tree wildcards are\nnever allowed in alternatives, such as `{a,**}`. Such an alternative is\nequivalent to a tree wildcard `**`, which should be used instead.\n\nRegarding the above limitations, note that tree wildcards parse any surrounding\nforward slashes `/`, so `a/{/**/b,c}` is allowed despite appearing to have\nadjacent path separators; the leading `/` in the sub-glob `/**/b` is parsed as a\ntree wildcard and **not** an independent path separator.\n\n### Literals and Platform-specific Features\n\nAny components not recognized by globs are interpreted as literals. In\ncombination with strict interpretations of path separators, this means some\nplatform-specific features cannot be used as part of a from-pattern.\n\nIn particular, while from-patterns can be rooted, they cannot include schemes\nnor Windows path prefixes. On Windows, UNC paths or paths with other prefixes\ncan be used via the `--tree`/`-C` option, which establishes the directory in\nwhich from-patterns are applied using native paths. For example, the following\ncommand copies all files from the UNC share path `\\\\server\\share\\src`.\n\n```shell\nnym copy -p --tree=\\\\server\\share 'src/**' 'C:\\\\backup\\\\{#1}'\n```\n\nGlobs do not explicitly support the notion of a parent directory. However, any\ninvariant (literal) prefix is re-interpreted by the platform as a native path,\nso from-patterns that begin with `..` behave as expected on Unix and Windows.\nFor example, the following command intuitively operates in the parent of the\ncurrent working directory.\n\n```shell\nnym find '../src/*.rs'\n```\n\nHowever, `..` is interpreted as a literal and when it follows variant\n(non-literal) components in a glob it only matches paths with the literal\ncomponent `..`. This never occurs when traversing directory trees, **so `..`\nliterals following variant patterns like wildcards match nothing and should not\nbe used**. For example, the from-pattern `src/**/../*.rs` never yields any\nmatching files.\n\n## To-Patterns\n\nTo-patterns resolve destination paths. These patterns consist of literals and\nsubstitutions. A substitution is either a capture from a corresponding\nfrom-pattern or a property that reads file metadata. Substitutions are delimited\nby curly braces `{...}`. Literals form a native path as-is.\n\n### Captures\n\nCaptures index a from-pattern using a hash followed by the index, like `{#1}`.\nThese indices count from one; the zero index is used for the full text of a\nmatch. Empty braces also represent the full text of a match, so `{#0}` and `{}`\nare equivalent.\n\nCaptures may include a condition. Conditions specify substitution text based on\nwhether or not the match text is empty. Conditions follow capture identifiers\nusing a ternary-like syntax: they begin with a question mark `?` followed by the\nnon-empty case, a colon `:`, and finally the empty case. Each case supports\nliterals, which specify alternative text delimited by square brackets `[...]`.\nIn the non-empty case, a surrounding prefix and postfix can be used instead\nusing two comma separated literals `[...],[...]`. Condition cases and\nsubstitution text may be empty.\n\nFor example, `{#1?[],[-]:}` is replaced by the matching text of the first\ncapture and, when that text is **non-empty**, is followed by the postfix `-`.\n`{#1?:[unknown]}` is replaced by the matching text of the first capture and,\nwhen that text is **empty**, is replaced by the literal `unknown`.\n\n### Properties\n\nProperties include source file metadata in the destination path and are\nspecified by name following an exclamation mark `!`. Property names are case\ninsensitive. Supported properties are described in the following table.\n\n| Pattern     | Metadata               | Type / Format | Cargo Feature               |\n|-------------|------------------------|---------------|-----------------------------|\n| `{!b3sum}`  | [BLAKE3] hash digest   | digest        | `property-b3sum` (default)  |\n| `{!ctime}`  | creation timestamp     | date-time     | n/a                         |\n| `{!md5sum}` | [MD5] hash digest      | digest        | `property-md5sum` (default) |\n| `{!mtime}`  | modification timestamp | date-time     | n/a                         |\n\nFor example, `{!b3sum}` is replaced by the [BLAKE3] hash digest of the matched\nfile.\n\nProperties are associated with a data type and corresponding format that\ntransforms them into the output text of a substitution. Formats are optionally\nspecified after a property name following a colon `:` and delimited by square\nbrackets `[...]`. For example, the date-time data type uses a [`strftime`]-like\nformat and the pattern `{!mtime:[%Y]}` outputs the text of the four-digit year\nof a source file's modification timestamp.\n\nProperties may require additional dependencies and some can be toggled in a\nbuild using [Cargo features][features].\n\n### Text Formatters\n\nSubstitutions (both captures and properties) support optional text formatters.\nText formatters must appear last in a substitution following a vertical bar `|`.\nAny number of text formatters may be used separated by commas `,` and they are\napplied from left to right in the order in which they appear.\n\nText formatters are distinct from property formats and, as their name suggests,\noperate exclusively on the output text of a substitution (they do not operate on\nnon-textual data).\n\nThe pad formatter pads substitution text to a specified width and alignment\nusing the given character shim. For example, `{#1|\u003e4[0]}` pads the substitution\ntext into four columns using right alignment and the character `0` for padding.\nIf the original substitution text is `13`, then it becomes `0013` after\nformatting in this example. Left and center alignment are also supported via `\u003c`\nand `^`, respectively.\n\nThere are three casing formatters: lowercase, uppercase, and titlecase, with the\ncase-insensitive patterns `lower`, `upper`, and `title`, respectively. These\nformatters take no parameters and change the casing of supported characters.\nNote that `title` is sensitive to word breaks, which only occur across\nwhitespace and hyphens `-` (and **not** underscores `_`, for example).\n\nThe coalesce formatter replaces matching input characters with an output\ncharacter. For example, `{#1|%[_-][~]}` replaces any instances of `_` or `-`\nwith a tilde `~`.\n\nText formatters can be combined to perform complex formatting. For example, the\nfollowing command extracts a part of file names delimited by underscores `_` and\nformats that part using title casing with spaces.\n\n```shell\nnym move '$_$_*.mp4' '{#2|%[-][ ],title}.mp4'\n```\n\nGiven a file named `the-show-title_the-episode-title_the-encoding.mp4`, the\nabove transform would move it to `The Episode Title.mp4`.\n\n## Crates\n\nNym's core functionality is exposed as an independent library and front ends are\ndeveloped atop this library. The following table describes the official Rust\ncrates maintained in the [Nym repository][repository].\n\n| Crate       | Description                                        |\n|-------------|----------------------------------------------------|\n| [`nym`]     | Library implementing Nym's core functionality.     |\n| [`nym-cli`] | Binary for the `nym` command line interface (CLI). |\n\nThe major and minor versions of these crates are upgraded together.\n\n## Installation\n\nThe `nym` binary can be installed in various ways described below.\n\n### Repository\n\nTo install `nym` from a clone of the repository, [install Rust][rustup] and then\nbuild and install `nym` using `cargo`. Nym requires Rust 1.51 or higher.\n\n```shell\ngit clone https://github.com/olson-sean-k/nym.git\ncd nym/nym-cli\ncargo install --locked --path=. --force\n```\n\nBy default, this will build the `master` branch, which generally tracks tested\nupcoming changes. To install a specific release, checkout a version tag before\nusing `cargo install`. Note that the build instructions may differ between\nversions; refer to the `README` in the clone.\n\n```shell\ngit checkout v0.0.0\n```\n\n### Registry\n\nTo install a release of `nym` from the [crates.io] Rust package registry,\n[install Rust][rustup] and then build and install `nym` using `cargo`.\n\n```shell\ncargo install nym-cli --locked --force\n```\n\nTo install a specific release, use the `--version` option.\n\n```shell\ncargo install nym-cli --version=0.0.0 --locked --force\n```\n\n### Package\n\nThe following table describes packages that can be used to install `nym`.\n\n| Platform   | Package                      |\n|------------|------------------------------|\n| Arch (AUR) | [`nym-git`][pkg-aur-nym-git] |\n\n## Disclaimer\n\nNym is provided as is and with **no** warranty. At the time of writing, Nym is\nexperimental and likely has bugs. Data loss may occur. **Use at your own risk.**\n\n[repository]: https://github.com/olson-sean-k/nym\n\n[BLAKE3]: https://github.com/BLAKE3-team/BLAKE3\n[crates.io]: https://crates.io\n[features]: https://doc.rust-lang.org/cargo/reference/features.html\n[MD5]: https://en.wikipedia.org/wiki/MD5\n[rustup]: https://rustup.rs/\n[`strftime`]: https://docs.rs/chrono/0.4.19/chrono/format/strftime/index.html\n\n[`nym`]: https://crates.io/crates/nym\n[`nym-cli`]: https://crates.io/crates/nym-cli\n\n[pkg-aur-nym-git]: https://aur.archlinux.org/packages/nym-git/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folson-sean-k%2Fnym","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Folson-sean-k%2Fnym","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Folson-sean-k%2Fnym/lists"}