{"id":34097466,"url":"https://github.com/minyus/recurtx","last_synced_at":"2026-03-10T09:02:05.347Z","repository":{"id":176720800,"uuid":"655547200","full_name":"Minyus/recurtx","owner":"Minyus","description":null,"archived":false,"fork":false,"pushed_at":"2025-04-12T10:20:36.000Z","size":117,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-12-16T20:52:09.811Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Minyus.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":null,"dco":null,"cla":null}},"created_at":"2023-06-19T06:02:25.000Z","updated_at":"2025-04-12T10:20:40.000Z","dependencies_parsed_at":"2024-01-07T12:43:47.360Z","dependency_job_id":"67de04a0-0289-4624-ba38-77201a1422b9","html_url":"https://github.com/Minyus/recurtx","commit_stats":null,"previous_names":["minyus/recurtx"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Minyus/recurtx","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Minyus%2Frecurtx","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Minyus%2Frecurtx/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Minyus%2Frecurtx/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Minyus%2Frecurtx/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Minyus","download_url":"https://codeload.github.com/Minyus/recurtx/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Minyus%2Frecurtx/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30328269,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-10T05:25:20.737Z","status":"ssl_error","status_checked_at":"2026-03-10T05:25:17.430Z","response_time":106,"last_error":"SSL_read: 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":[],"created_at":"2025-12-14T15:57:16.072Z","updated_at":"2026-03-10T09:02:05.320Z","avatar_url":"https://github.com/Minyus.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# recurtx\n\n[![Python version](https://img.shields.io/badge/python-3.7%20%7C%203.8%20%7C%203.9-blue.svg)](https://pypi.org/project/recurtx/)\n[![PyPI version](https://badge.fury.io/py/recurtx.svg)](https://badge.fury.io/py/recurtx)\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/Minyus/recurtx/blob/main/LICENSE)\n\nCLI to recursively search and transform text files in xargs style\n\n## Key features\n\n- search and substitute (replace) text in file contents or file paths in place\n- installable without sudo (using pip)\n\n## Background\n\nThis tool was developed as an opinionated (partial) alternative to the following CLI tools.\n\n- `find` to recursively find file paths\n- `fd` to recursively find file paths respecting .gitignore (`fd` is internally used by `xunder` and `xbatch` in default if installed)\n- `grep` to search text\n- [`rg`](https://github.com/BurntSushi/ripgrep) to search text\n- [`ag`](https://github.com/ggreer/the_silver_searcher) to search text\n- `sed` to modify text\n- `xargs` to repeat similar to for-loop\n- `tree` to recursively check file paths\n- `du` to check disk usage\n- [`csvkit`](https://csvkit.readthedocs.io/en/latest/) to search (and modify) text in csv files\n- [`spyql`](https://spyql.readthedocs.io/) to search (and modify) text in csv files\n- [`clickhouse-local`](https://clickhouse.com/docs/en/operations/utilities/clickhouse-local)\n- [`polars-cli`](https://github.com/pola-rs/polars-cli) to search text in csv files\n- [`csvlens`](https://github.com/YS-L/csvlens) to view csv files\n- [`rich-cli`](https://github.com/Textualize/rich-cli) to view csv files\n\nThis tool is quicker to write although execution might be slower depending on the amount of your text data.\n\n## Install\n\nPrerequisite: Python 3 (3.8 or later recommended)\n\n### [Option 1] Install from PyPI\n\n```\npip install recurtx\n```\n\n### [Option 2] Install from source code\n\nThis is recommended only if you want to modify the source code.\n\n```bash\ngit clone https://github.com/Minyus/recurtx.git\ncd recurtx\npython setup.py develop\n```\n\n## Wrapper Commands\n\n### xunder\n\nRun any scripts for each file under a directory recursively.\n\n#### Examples\n\nRun `wc -l {FILEPATH}` for each file under `directory_foo` recursively:\n\n```\nxunder directory_foo \"wc -l\"\n```\n\nQuoting for the script can be omitted for most cases.\n\n```\nxunder directory_foo wc -l\n```\n\nCaveat: int, float, tuple, list, dict could be formatted unexpectedly (by `fire` package), for example:\n\n- ` 00 ` (recognized as int by Python) will be converted to ` 0 ` while ` \"00\" ` (recognized as str by Python) will be kept as is\n\n#### Description\n\n```\nNAME\n    xunder\n\nSYNOPSIS\n    xunder PATH \u003cflags\u003e [SCRIPTS]...\n\nPOSITIONAL ARGUMENTS\n    PATH\n        Type: str\n    SCRIPTS\n        Type: str\n\nFLAGS\n    --glob=GLOB\n        Type: str\n        Default: '**/*'\n    --replace_str=REPLACE_STR\n        Type: str\n        Default: '@@'\n    --show_paths=SHOW_PATHS\n        Type: bool\n        Default: False\n    --show_scripts=SHOW_SCRIPTS\n        Type: bool\n        Default: False\n\nNOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS\n```\n\n### xbatch\n\nRun any scripts for a batch of files in a directory recursively.\n\n#### Examples\n\nConcatenate all the contents in directory_foo.\n\n```\nxbatch directory_foo cat\n```\n\n#### Description\n\n```\nNAME\n    xbatch\n\nSYNOPSIS\n    xbatch PATH \u003cflags\u003e [SCRIPTS]...\n\nPOSITIONAL ARGUMENTS\n    PATH\n        Type: str\n    SCRIPTS\n        Type: str\n\nFLAGS\n    --glob=GLOB\n        Type: str\n        Default: '**/*'\n    --replace_str=REPLACE_STR\n        Type: str\n        Default: '@@'\n    --show_paths=SHOW_PATHS\n        Type: bool\n        Default: False\n    --show_scripts=SHOW_SCRIPTS\n        Type: bool\n        Default: False\n\nNOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS\n```\n\n## Commands to transform text files\n\n### xsearch\n\nSearch a keyword, which may include wildcards, in the text file content, and optionally substitute (replace).\n\n#### Examples\n\nSearch `keyword_bar` in each file under `directory_foo` recursively:\n\n```\nxunder directory_foo xsearch keyword_bar\n```\n\nSearch `keyword_bar` and substitute (replace) with `keyword_baz` in each file under `directory_foo` recursively:\n\n```\nxunder directory_foo xsearch keyword_bar --sub keyword_baz\n```\n\n#### Description\n\n```\nNOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS\n\nNAME\n    xsearch - Search a keyword, which may include wildcards, in the text file content, and optionally substitute (replace).\n\nSYNOPSIS\n    xsearch TARGET PATH \u003cflags\u003e\n\nDESCRIPTION\n    Search a keyword, which may include wildcards, in the text file content, and optionally substitute (replace).\n\nPOSITIONAL ARGUMENTS\n    TARGET\n        Type: str\n    PATH\n        Type: str\n\nFLAGS\n    --sub=SUB\n        Type: Optional[typing.Unio...\n        Default: None\n    -w, --wildcard=WILDCARD\n        Type: str\n        Default: '*'\n    --separator=SEPARATOR\n        Type: str\n        Default: '/'\n    -v, --verbose=VERBOSE\n        Type: int\n        Default: 1\n    -c, --context=CONTEXT\n        Type: typing.Union[int, NoneType]\n        Default: 1\n    -p, --plain=PLAIN\n        Type: bool\n        Default: False\n\nNOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS\n```\n\n### xfind\n\nFind a keyword, which may include wildcards, in the file path, and optionally substitute (replace).\n\n#### Examples\n\nSearch `keyword_bar` in each file path under `directory_foo` recursively:\n\n```\nxunder directory_foo xfind keyword_bar\n```\n\nSearch `keyword_bar` and substitute (replace) with `keyword_baz` in each file path under `directory_foo` recursively:\n\n```\nxunder directory_foo xfind keyword_bar --sub keyword_baz\n```\n\n#### Description\n\n```\nNAME\n    xfind\n\nSYNOPSIS\n    xfind TARGET PATH \u003cflags\u003e\n\nPOSITIONAL ARGUMENTS\n    TARGET\n        Type: str\n    PATH\n        Type: str\n\nFLAGS\n    -s, --sub=SUB\n        Type: Optional[str]\n        Default: None\n    -w, --wildcard=WILDCARD\n        Type: str\n        Default: '*'\n    -v, --verbose=VERBOSE\n        Type: int\n        Default: 1\n\nNOTES\n    You can also use flags syntax for POSITIONAL ARGUMENTS\n```\n\n### xll\n\nAlternative to `ls -lah` and `du`.\nShow approximate total size and max size in Bytes to respond quickly in default while it takes time to run `du` in a big directory including many files.\nShow number of files and the most common file extention(s) as well.\n\n#### Examples\n\nRun under `directory_foo` non-recursively (up to depth 1):\n\n```\nxll directory_foo\n```\n\nRun under `directory_foo` recursively up to depth 2:\n\n```\nxll -d 2 directory_foo\n```\n\n#### Description\n\n```\nNAME\n    xll - Compute statistics for the directory recursively.\n\nSYNOPSIS\n    xll \u003cflags\u003e [PATHS]...\n\nDESCRIPTION\n    Compute statistics for the directory recursively.\n\nPOSITIONAL ARGUMENTS\n    PATHS\n        Type: str\n\nFLAGS\n    -d, --depth=DEPTH\n        Type: int\n        Default: 1\n    -u, --unit_glob=UNIT_GLOB\n        Type: str\n        Default: '**/*'\n    -t, --type=TYPE\n        Type: Optional[typing.Unio...\n        Default: None\n    -g, --glob=GLOB\n        Type: str\n        Default: '**/*'\n    -r, --regex=REGEX\n        Type: str\n        Default: '^(?!.*(\\\\.git\\\\/|__pycache__\\\\/|\\\\.ipynb_checkpoints\\\\/|\\\\....\n    -n, --number_limit=NUMBER_LIMIT\n        Type: int\n        Default: 100\n    -s, --sort_paths=SORT_PATHS\n        Type: str\n        Default: 'asc'\n    -i, --info=INFO\n        Type: bool\n        Default: True\n    -e, --extension_most_common=EXTENSION_MOST_COMMON\n        Type: int\n        Default: 1\n```\n\n### xpandas\n\nRead and transform tabular data using pandas.\n\nRegarding options, see the documents for `pandas.read_xxx` such as:\n\n- [pandas.read_csv](https://pandas.pydata.org/docs/reference/api/pandas.read_csv.html)\n\nData types supported by pandas (not all were tested):\n\n- \"pickle\"\n- \"table\"\n- \"csv\"\n- \"fwf\"\n- \"clipboard\"\n- \"excel\"\n- \"json\"\n- \"html\"\n- \"xml\"\n- \"hdf\"\n- \"feather\"\n- \"parquet\"\n- \"orc\"\n- \"sas\"\n- \"spss\"\n- \"sql_table\"\n- \"sql_query\"\n- \"sql\"\n- \"gbq\"\n- \"stata\"\n\n#### Install dependency\n\n```\npip install pandas\n```\n\n#### Examples\n\nRead files supported by pandas (such as csv and json) under directory_foo and concatenate:\n\n```\nxbatch directory_foo xpandas\n```\n\n### xpolars\n\nRead and transform tabular data using polars.\n\nRegarding options, see the documents for `polars.scan_xxx` (or `polars.read_xxx` if scan function is not available), such as:\n\n- [polars.scan_csv](https://pola-rs.github.io/polars/py-polars/html/reference/api/polars.scan_csv.html)\n\nData types supported by polars (not all were tested):\n\n- \"csv\"\n- \"ipc\"\n- \"parquet\"\n- \"database\"\n- \"json\"\n- \"ndjson\"\n- \"avro\"\n- \"excel\"\n- \"delta\"\n\n#### Install dependency\n\n```\npip install polars\n```\n\n#### Examples\n\nRead files supported by polars (such as csv and json) under directory_foo and concatenate:\n\n```\nxbatch directory_foo xpolars\n```\n\n## Dependency to enable CLI\n\n- \u003chttps://github.com/google/python-fire\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminyus%2Frecurtx","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fminyus%2Frecurtx","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fminyus%2Frecurtx/lists"}