{"id":17790968,"url":"https://github.com/catatsuy/purl","last_synced_at":"2026-02-07T08:04:05.929Z","repository":{"id":228151846,"uuid":"773279401","full_name":"catatsuy/purl","owner":"catatsuy","description":"Streamlining Text Processing","archived":false,"fork":false,"pushed_at":"2026-02-02T20:11:50.000Z","size":270,"stargazers_count":229,"open_issues_count":2,"forks_count":6,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-03T10:32:20.632Z","etag":null,"topics":["grep-like","regexp","sed","text-processing"],"latest_commit_sha":null,"homepage":"","language":"Go","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/catatsuy.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-03-17T08:24:18.000Z","updated_at":"2026-01-17T06:00:32.000Z","dependencies_parsed_at":"2025-11-22T10:12:13.294Z","dependency_job_id":null,"html_url":"https://github.com/catatsuy/purl","commit_stats":null,"previous_names":["catatsuy/purl"],"tags_count":15,"template":false,"template_full_name":null,"purl":"pkg:github/catatsuy/purl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catatsuy%2Fpurl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catatsuy%2Fpurl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catatsuy%2Fpurl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catatsuy%2Fpurl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/catatsuy","download_url":"https://codeload.github.com/catatsuy/purl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/catatsuy%2Fpurl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29189675,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-07T07:37:03.739Z","status":"ssl_error","status_checked_at":"2026-02-07T07:37:03.029Z","response_time":63,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["grep-like","regexp","sed","text-processing"],"created_at":"2024-10-27T10:48:39.220Z","updated_at":"2026-02-07T08:04:05.888Z","avatar_url":"https://github.com/catatsuy.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Purl\n\nPurl is a command-line utility designed for text file parsing and manipulation, offering a modern alternative to traditional sed and perl one-liners. It features intuitive options for filtering, transforming, and managing text data. Importantly, Purl accepts both file input and standard input, providing flexibility for various workflows. Moreover, it supports multiple instances of the -filter and -exclude options, allowing users to apply complex patterns of search refinements and exclusions in a single command.\n\nUnlike sed, Purl works the same way on both Mac and Linux, without any compatibility issues. Simply download it to start using, offering a straightforward experience for text manipulation.\n\n## Inspiration Behind \"Purl\"\n\nThe name \"Purl\" comes from a knitting technique and the sound of a flowing river. In knitting, \"purling\" is a way to create smooth fabric by repeating certain stitches. Similarly, the sound of a river is continuous and calming. \"Purl\" represents how this tool helps you transform text smoothly, just like the consistent pattern of knitting and the steady flow of a river. It is designed to use simple commands like Perl to make complex text tasks easy.\n\n## Why purl?\n\nOlder tools like sed and grep have problems:\n\n- **Complex Regex**: They use a regex that is not like Perl's, which is hard to use.\n- **Not Compatible**: sed does not work the same on macOS and Linux, leading to problems.\n\nI used Perl before because it is easier for regex and works well on different systems. But Perl has issues too:\n\n- **Not Installed by Default**: New versions of macOS and Linux do not have Perl already installed, which makes it hard to use, especially in Docker.\n- **Less Popular**: Fewer people use Perl now, so it seems less appealing.\n- **Not Just for One-Liners**: Perl is not just for quick commands, which can make it confusing.\n\nWe need a new tool that:\n\n- **Uses Easy Perl-Like Regex**: Easy to use for handling text using Go's regexp.\n- **Works on All Systems**: No problems with different operating systems.\n- **Light and Easy to Install**: Easy to set up anywhere.\n- **Simple Commands**: Easy to understand, even for beginners.\n\nSo, I made **purl**. It brings together Perl's best parts but is simpler and ready for today's users.\n\n## demo\n\nThis demo highlights how Purl utilizes both `-filter` and `-exclude` options to pinpoint essential lines within a log file, streamlining the search for relevant data.\n\nhttps://github.com/catatsuy/purl/assets/1249910/72c01b33-082f-4b7f-84bc-4c59b0859df9\n\nThis demo shows how to use Purl to change `http://` URLs to `https://` in a source code file, using the `-replace` and `-overwrite` options to update the file directly.\n\nhttps://github.com/catatsuy/purl/assets/1249910/be87d17a-44e7-4091-bc80-77921174eac2\n\nThis demo demonstrates using Purl to remove comments and empty lines from a configuration file, employing both `-filter` and `-exclude` options along with `-overwrite` to directly modify the file.\n\nhttps://github.com/catatsuy/purl/assets/1249910/5cc479cc-ce1c-4901-864d-963bf659e125\n\n## Features\n\n**purl** is a tool that helps you easily handle data from different sources. Here are its main features:\n\n- **Flexible Data Input and Output**: You can input data from typing directly or from files. Similarly, you can choose to output data directly to your screen or save it back to files.\n- **Extract Specific Text**: The `-extract` option lets you extract and format specific parts of the text using regular expressions. For example, you can capture groups in the pattern and use them in a custom output format.\n- **Simple Commands**: Use straightforward options like `-replace`, `-filter`, `-exclude`, and `-extract` to manage your data.\n- **Edit Files Easily**: The `-overwrite` option lets you update files directly, making changes quick and simple.\n- **Colorful Output**: When using the `-filter` option, the output on your screen can be colorful. You can control this with the `-color` or `-no-color` options.\n- **Error on No Matches**: With the `-fail` option, Purl returns an error (status code 1) if no matches are found when using `-filter`, `-replace`, or `-extract`. If not used, Purl will not return an error even if no matches are found.\n\nThis tool is made to be user-friendly and effective for different data handling tasks.\n\n## Input Processing Modes\n\nPurl has two ways to read input:\n\n1. **Multi-Line Mode (For Files)**\n   When you use a file, purl reads the whole file at once. This lets you use regular expressions that match across multiple lines. However, it waits until the file is finished, so it is not good for live data (like piped input).\n\n2. **Line Mode (For Standard Input)**\n   When you do not give a file (using standard input), purl automatically uses **line mode**. In this mode, purl reads one line at a time and prints the output immediately. You can also force this mode by using the `-line` option.\n\n   **Examples:**\n   - To process data from a file or pipe and force line-by-line reading:\n     ```bash\n     cat yourfile.txt | purl -line -replace \"@search@replace@\"\n     ```\n   - If no file is given, purl uses line mode by default so it does not wait forever:\n     ```bash\n     purl -line -filter \"error\"\n     ```\n\nThis way, purl outputs data quickly when reading live input, and still supports multi-line matching when reading files.\n\n### Regular Expressions and Multi-Line Mode in Purl\n\nPurl uses Go's `regexp` package with **Multi-Line Mode** (`(?m)`) always enabled. This makes line-based text processing intuitive and powerful.\n\n#### What is Multi-Line Mode?\n\nIn Multi-Line Mode:\n- `^` matches the start of a line.\n- `$` matches the end of a line, just before the newline character (`\\n`).\n\nThis mode is particularly useful when working with text files, as it aligns regular expressions with line-based operations.\n\nHere’s a simplified and clear explanation for the README:\n\n### Special Case: Empty Lines\n\nWhen using `^$`, it matches completely empty lines with zero characters. However, lines that only contain a newline character (`\\n`) are not considered \"empty\" in Go's `regexp`.\n\nIf you want to match and exclude lines that only contain a newline (`\\n`), you should use `^\\n$` instead.\n\n#### Example\n\n**Input:**\n```\nline1\n\nline2\nline3\n\n```\n\n**Command:**\n```bash\npurl -exclude \"^\\n$\" file.txt\n```\n\n**Output:**\n```\nline1\nline2\nline3\n```\n\n## Installation\n\nIt is recommended that you use the binaries available on [GitHub Releases](https://github.com/catatsuy/purl/releases). It is advisable to download and use the latest version.\n\nIf you have a Go language development environment set up, you can also compile and install the 'purl' tools on your own.\n\n```bash\ngo install github.com/catatsuy/purl@latest\n```\n\nTo build and modify the 'purl' tools for development purposes, you can use the `make` command.\n\n```bash\nmake\n```\n\nIf you use the `make` command to build and install the 'purl' tool, the output of the `purl -version` command will be the git commit ID of the current version.\n\n### Using Purl with GitHub Actions\n\nIf you want to use Purl in your GitHub Actions workflows, include the following steps in your `.github/workflows` YAML file:\n\n```yaml\n- name: Download purl\n  run: |\n    curl -sL https://github.com/catatsuy/purl/releases/latest/download/purl-linux-amd64.tar.gz | tar xz -C /tmp\n\n- name: Move purl to /usr/local/bin\n  run: |\n    sudo mv /tmp/purl /usr/local/bin/\n```\n\nThese steps ensure that Purl is downloaded and moved to `/usr/local/bin`, making it available for use in subsequent steps of your workflow.\n\n### Why Use Multi-Line Mode?\n\nPurl's default Multi-Line Mode (`(?m)`) simplifies operations like filtering, replacing, and excluding lines. You don't need to manually include `(?m)` in your patterns—it's always enabled for you.\n\n#### Example Use Cases\n\n1. **Filter Lines Starting with a Word**\n   ```bash\n   purl -filter \"^START\" file.txt\n   ```\n\n   Matches lines that start with `START`.\n\n2. **Exclude Empty Lines**\n   ```bash\n   purl -exclude \"^\\n$\" file.txt\n   ```\n\n   Removes lines that only contain a newline (`\\n`).\n\n3. **Replace Text on Specific Lines**\n   ```bash\n   purl -replace \"@^line1@REPLACED@\" file.txt\n   ```\n\n   Replaces lines starting with `line1` with `REPLACED`.\n\n## Usage Examples\n\n### Preview Changes Before Applying\n\n```bash\npurl -replace \"@search@replace@\" yourfile.txt\n```\n\nThis command searches for \"search\" in `yourfile.txt`, shows how it would be replaced with \"replace\", but does not modify the file itself.\n\n### Directly Modify Files\n\n```bash\npurl -overwrite -replace \"@search@replace@\" yourfile.txt\n```\n\nUsing the `-overwrite` option, Purl will replace \"search\" with \"replace\" in `yourfile.txt` and save the changes to the file.\n\n### Using Standard Input\n\nPurl can also process input piped from other commands, offering flexibility in how it's used:\n\n```bash\ncat yourfile.txt | purl -replace \"@search@replace@\"\n```\n\nThis feeds the content of `yourfile.txt` into Purl, which processes and displays the modified text according to the specified replacement pattern.\n\n### Using multiple files\n\nPurl supports processing multiple files in a single command, allowing you to apply operations across several documents simultaneously. Simply list the files at the end of your command. For example:\n\n```bash\npurl -replace \"@search@replacement@\" file1.txt file2.txt file3.txt\n```\n\nThis command will apply the replace operation to 'search' with 'replacement' in `file1.txt`, `file2.txt`, and `file3.txt`.\n\n### Usage with `-filter`\n\n```bash\npurl -filter \"error\" yourlog.log\n```\n\nThis command filters the lines containing \"error\" in `yourlog.log`, displaying them with colored output for better visibility.\n\n### Extracting Specific Parts of Text\n\nThe `-extract` option allows you to capture specific parts of the text using regular expressions and output them in a custom format.\n\n```bash\npurl -extract \"@quick ([a-z]+) fox@animal: $1@\" yourfile.txt\n```\n\nThis command captures the word after \"quick\" and before \"fox\" and formats it as `animal: \u003ccaptured_word\u003e`. For example, given the input:\n\n```\nThe quick brown fox jumps over the lazy dog\nquick red fox\n```\n\nThe output will be:\n\n```\nanimal: brown\nanimal: red\n```\n\nYou can also use multiple capture groups to format more complex outputs:\n\n```bash\npurl -extract \"@(\\\\w+) (\\\\w+) (\\\\w+)@Match: $1, $2, $3@\" yourfile.txt\n```\n\nWith the input:\n\n```\napple banana cherry\ngrape orange pineapple\n```\n\nThe output will be:\n\n```\nMatch: apple, banana, cherry\nMatch: grape, orange, pineapple\n```\n\n### Using the `-fail` Option\n\n```bash\npurl -fail -filter \"error\" yourlog.log\n```\n\nThis command will search for lines containing \"error\" in `yourlog.log` and return an error (status code 1) if no matches are found. This behavior is useful for scripts where the absence of a match should trigger an error.\n\n### Combining `-fail` with `-replace`\n\n```bash\npurl -fail -replace \"@search@replace@\" yourfile.txt\n```\n\nIn this example, if no instances of \"search\" are found in `yourfile.txt`, Purl will return an error, indicating that no replacements were made.\n\nThese additions should provide a clear explanation of the new `-fail` option, helping users understand how to use it effectively in their workflows.\n\n### Filtering Input with Multiple Criteria\n\nTo filter lines that meet multiple criteria, you can use the `-filter` option multiple times. This works both when reading from a file and processing standard input.\n\n```bash\npurl -filter \"error\" -filter \"warning\" yourlog.log\n```\n\nOr for standard input:\n\n```bash\ncat yourlog.log | purl -filter \"error\" -filter \"warning\"\n```\n\nThis will display lines that contain either \"error\" or \"warning\" from `yourlog.log`.\n\n### Excluding Lines with Multiple Patterns\n\nSimilarly, you can exclude lines that match multiple patterns by specifying `-exclude` more than once:\n\n```bash\npurl -exclude \"debug\" -exclude \"info\" yourlog.log\n```\n\nOr for piped input:\n\n```bash\ncat yourlog.log | purl -exclude \"debug\" -exclude \"info\"\n```\n\nThis approach excludes lines that contain \"debug\" or \"info\" from the output.\n\nPurl allows combining `-filter` and `-exclude` for precise text control.\n\n### Using the -i Option for Case-Insensitive Searches\n\nWhen the `-i` option is used with Purl, it allows case-insensitive matching for filters and exclusions. For instance:\n\n```bash\npurl -i -filter \"error\" yourfile.txt\n```\n\nThis command will match lines containing 'error' in any case variation, such as 'Error', 'ERROR', or 'error', in `yourfile.txt`.\n\nThe `-i` option in Purl enables case-insensitive operations not only for `-filter` but also for `-exclude` and `-replace`. This enhances flexibility in handling text variations. For example:\n\n```bash\npurl -i -exclude \"debug\" yourfile.txt\n```\n\nThis will exclude lines with 'debug', 'Debug', 'DEBUG', etc., from `yourfile.txt`.\n\nSimilarly, when using `-replace`:\n\n```bash\npurl -i -replace \"@search@replacement@\" yourfile.txt\n```\n\nThis applies the replacement operation regardless of case differences between 'search' and its occurrences in `yourfile.txt`, ensuring 'Search', 'SEARCH', etc., are also matched and replaced.\n\n### Integrating with Git, Grep, and Xargs\n\nFor users looking to apply replacements across multiple files in a Git repository:\n\n```bash\ngit grep -l 'search_pattern' | xargs purl -overwrite -replace \"@search_pattern@replace_text@\"\n```\n\nThis sequence finds all files containing 'search_pattern', then uses Purl to replace it with 'replace_text', directly modifying the files where the changes are applied.\n\nPurl is crafted to offer simplicity for quick tasks as well as the capability to perform complex text processing, embodying the spirit of its name in every action it performs.\n\n## Tips and Tricks\n\n- **Using Special Characters**: Purl supports special characters like `\\n` (newline), `\\t` (tab), and `\\r` (carriage return) in both patterns and replacements. For example:\n\n```bash\npurl -replace \"@pattern@\\nreplacement@\" file.txt\n```\n\nThis replaces occurrences of `pattern` followed by a newline and text in the file with replacement.\n\n- **Handling Single Quotes**: When using single quotes or other special characters that conflict with shell syntax, you can combine different quoting styles. For example:\n\n```bash\npurl -replace '@pattern@'\"'\"'replacement'\"'\"'@' file.txt\n```\n\nHere, `'\"'\"'` is used to escape the single quote within the single-quoted string.\n\nThese tips can help you effectively use Purl in more complex scenarios while navigating shell-specific limitations.\n\n## FAQ\n\n### What can I do with regular expressions?\n\nThis tool uses Go's [`regexp` package](https://pkg.go.dev/regexp) directly. So, any pattern supported by Go's regular expressions can be used.\n\n### Can I use characters other than '@' in the `-replace` option?\n\nYes, you can use different characters besides '@' for the `-replace` option. You just need to make sure the character you choose is not in your pattern or replacement.\n\nIf you want to use a different character, like '#', you can do it like this:\n\n```bash\npurl -replace \"#pattern#replacement#\" file.txt\n```\n\nBe sure your character is not part of your pattern or replacement text.\n\n### Why Doesn't `-exclude '^$'` Work for Empty Lines?\n\nIn Go's `regexp`:\n\n- `^$` matches lines that are completely empty (zero characters).\n- Lines with just a newline (`\\n`) contain one character and are not matched by `^$`.\n\nTo handle such lines, use `^\\n$` to explicitly match them.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcatatsuy%2Fpurl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcatatsuy%2Fpurl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcatatsuy%2Fpurl/lists"}