{"id":34042036,"url":"https://github.com/aureliojargas/sedparse","last_synced_at":"2026-04-08T15:31:22.315Z","repository":{"id":57465219,"uuid":"210212246","full_name":"aureliojargas/sedparse","owner":"aureliojargas","description":"GNU sed's parser translated from C to Python","archived":false,"fork":false,"pushed_at":"2024-03-20T16:32:23.000Z","size":208,"stargazers_count":13,"open_issues_count":8,"forks_count":3,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-12-15T14:33:06.000Z","etag":null,"topics":["parser","sed-scripts"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aureliojargas.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-09-22T20:48:36.000Z","updated_at":"2025-05-09T23:14:11.000Z","dependencies_parsed_at":"2023-01-22T01:04:01.309Z","dependency_job_id":null,"html_url":"https://github.com/aureliojargas/sedparse","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/aureliojargas/sedparse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aureliojargas%2Fsedparse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aureliojargas%2Fsedparse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aureliojargas%2Fsedparse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aureliojargas%2Fsedparse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aureliojargas","download_url":"https://codeload.github.com/aureliojargas/sedparse/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aureliojargas%2Fsedparse/sbom","scorecard":{"id":216523,"data":{"date":"2025-08-11","repo":{"name":"github.com/aureliojargas/sedparse","commit":"dc49fe00a3c6977bed4d4ddd9aa7955552d2cd01"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/check.yaml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/check.yaml:39: update your workflow using https://app.stepsecurity.io/secureworkflow/aureliojargas/sedparse/check.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/check.yaml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/aureliojargas/sedparse/check.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/check.yaml:13: update your workflow using https://app.stepsecurity.io/secureworkflow/aureliojargas/sedparse/check.yaml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/check.yaml:14: update your workflow using https://app.stepsecurity.io/secureworkflow/aureliojargas/sedparse/check.yaml/main?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: GNU General Public License v3.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Vulnerabilities","score":5,"reason":"5 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6","Warn: Project is vulnerable to: PYSEC-2025-49 / GHSA-5rjg-fvgr-3xxf","Warn: Project is vulnerable to: GHSA-cx63-2mw6-8hw5","Warn: Project is vulnerable to: PYSEC-2022-43012 / GHSA-r9hx-vwmv-q579","Warn: Project is vulnerable to: PYSEC-2022-43017 / GHSA-qwmp-2cf2-g9g6"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'main'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 5 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-17T01:44:51.080Z","repository_id":57465219,"created_at":"2025-08-17T01:44:51.080Z","updated_at":"2025-08-17T01:44:51.080Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31562685,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"ssl_error","status_checked_at":"2026-04-08T14:31:17.202Z","response_time":54,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5: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":["parser","sed-scripts"],"created_at":"2025-12-13T22:13:12.749Z","updated_at":"2026-04-08T15:31:22.306Z","avatar_url":"https://github.com/aureliojargas.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sedparse\n\n- Author: Aurelio Jargas\n- License: GPLv3\n- Tested with Python 2.7, 3.4, 3.5, 3.6, 3.7 and 3.8 (see [check.yaml](https://github.com/aureliojargas/sedparse/blob/main/.github/workflows/check.yaml))\n\nA translation from C to Python of GNU sed's parser for sed scripts.\n\nAfter running sedparse in your sed script, the complete list of all the found sed commands and their arguments will be available in different formats:\n\n- List of objects (translated C structs)\n- List of dictionaries\n- JSON\n\nFor a complete reference on how the different sed commands are mapped by the parser, see:\n\n- [tests/reference.sed](https://github.com/aureliojargas/sedparse/blob/main/tests/reference.sed) - original sed script\n- [tests/reference.json](https://github.com/aureliojargas/sedparse/blob/main/tests/reference.json) - JSON generated by sedparse\n\n\n## About the translation\n\nI copied the original code in C and translated everything to Python, line by line.\n\nTo make it feasible to keep this code updated with future GNU sed code, this is a literal translation, trying to mimic as much as possible of the original code. That includes using the same API, same logic, same variable and method names and same data structures. Pythonic code? Sorry, not here.\n\nThe accuracy of the parser is checked by extensive unit tests in [tests/](https://github.com/aureliojargas/sedparse/tree/main/tests).\n\nSedparse was translated from this GNU sed version:\n\nhttp://git.savannah.gnu.org/cgit/sed.git/commit/?id=a9cb52bcf39f0ee307301ac73c11acb24372b9d8\n\n    commit a9cb52bcf39f0ee307301ac73c11acb24372b9d8\n    Author: Assaf Gordon \u003cassafgordon@gmail.com\u003e\n    Date:   Sun Jun 2 01:14:00 2019 -0600\n\n\u003e Note that this is not a full GNU sed implementation.\n\u003e Only the parser for sed scripts was translated.\n\u003e Check https://github.com/GillesArcas/PythonSed for a working sed in Python.\n\n\n## Sedparse extensions to the original parser\n\n- Preserves comments\n- Preserves blank lines between commands\n- Preserves original flags for the `s` command\n- Preserves original flags for regex addresses\n\n\n## Installation\n\n    pip install --user sedparse\n    sedparse --help\n\nAlternatively, you can just download and run the [sedparse.py](https://raw.githubusercontent.com/aureliojargas/sedparse/main/sedparse.py) file, since it is self-contained with no external dependencies.\n\n\n## Usage from the command line\n\nThe informed sed script will be parsed and checked for syntax errors. If everything is fine, a JSON representation of the script is sent to STDOUT.\n\nJust like in sed, you can inform the sed script using one or more `-e` options:\n\n```console\n$ sedparse -e \"s/foo/bar/g\" -e \"5d\"\n[\n    {\n        \"cmd\": \"s\",\n        \"line\": 1,\n        \"x\": {\n            \"cmd_subst\": {\n                \"regx\": {\n                    \"flags\": \"g\",\n                    \"pattern\": \"foo\",\n                    \"slash\": \"/\"\n                },\n                \"replacement\": {\n                    \"text\": \"bar\"\n                }\n            }\n        }\n    },\n    {\n        \"a1\": {\n            \"addr_number\": 5,\n            \"addr_type\": 3\n        },\n        \"cmd\": \"d\",\n        \"line\": 1\n    }\n]\n$\n```\n\nOr you can inform the sed script as a file argument using `-f`:\n\n```console\n$ echo '1,10!d' \u003e head.sed\n$ sedparse -f head.sed\n[\n    {\n        \"a1\": {\n            \"addr_number\": 1,\n            \"addr_type\": 3\n        },\n        \"a2\": {\n            \"addr_number\": 10,\n            \"addr_type\": 3\n        },\n        \"addr_bang\": true,\n        \"cmd\": \"d\",\n        \"line\": 1\n    }\n]\n$ rm head.sed\n$\n```\n\nOr even as text coming from STDIN when using the special `-` file:\n\n```console\n$ echo '\\EXTREMITIES' | sedparse -f -\n[\n    {\n        \"a1\": {\n            \"addr_regex\": {\n                \"flags\": \"MI\",\n                \"pattern\": \"XTR\",\n                \"slash\": \"E\"\n            },\n            \"addr_type\": 2\n        },\n        \"cmd\": \"T\",\n        \"line\": 1,\n        \"x\": {\n            \"label_name\": \"IES\"\n        }\n    }\n]\n$\n```\n\n\n## Usage as a Python module\n\nUse `sedparse.compile_string()` to parse a string as a sed script. You must inform a list that will be appended in-place with the parsed commands.\n\n```python\n\u003e\u003e\u003e import sedparse\n\u003e\u003e\u003e sedscript = \"\"\"\\\n... 11,/foo/ {\n...     $!N\n...     s/\\\\n/-/gi\n... }\n... \"\"\"\n\u003e\u003e\u003e parsed = []\n\u003e\u003e\u003e sedparse.compile_string(parsed, sedscript)\n\u003e\u003e\u003e\n```\n\nEach sed command is represented by a `struct_sed_cmd` instance.\n\n```python\n\u003e\u003e\u003e import pprint\n\u003e\u003e\u003e pprint.pprint(parsed)  # doctest:+ELLIPSIS\n[struct_sed_cmd(line=1, cmd='{', ...),\n struct_sed_cmd(line=2, cmd='N', ...),\n struct_sed_cmd(line=3, cmd='s', ...),\n struct_sed_cmd(line=4, cmd='}', ...)]\n\u003e\u003e\u003e\n```\n\nYou can `str()` each command, or any of its inner structs, to get their \"human readable\" representation.\n\n```python\n\u003e\u003e\u003e [str(x) for x in parsed]\n['11,/foo/ {', '$ !N', 's/\\\\n/-/gi', '}']\n\u003e\u003e\u003e str(parsed[0])\n'11,/foo/ {'\n\u003e\u003e\u003e str(parsed[0].a1)\n'11'\n\u003e\u003e\u003e str(parsed[0].a2)\n'/foo/'\n\u003e\u003e\u003e\n```\n\nUse `.to_dict()` to convert a command into a Python dictionary.\n\n```python\n\u003e\u003e\u003e cmd_n = parsed[1]\n\u003e\u003e\u003e str(cmd_n)\n'$ !N'\n\u003e\u003e\u003e pprint.pprint(cmd_n.to_dict())\n{'a1': {'addr_type': 7}, 'addr_bang': True, 'cmd': 'N', 'line': 2}\n\u003e\u003e\u003e\n\u003e\u003e\u003e pprint.pprint(cmd_n.to_dict(remove_empty=False))\n{'a1': {'addr_number': 0, 'addr_regex': None, 'addr_step': 0, 'addr_type': 7},\n 'a2': None,\n 'addr_bang': True,\n 'cmd': 'N',\n 'line': 2,\n 'x': {'cmd_subst': {'outf': {'name': ''},\n                     'regx': {'flags': '', 'pattern': '', 'slash': ''},\n                     'replacement': {'text': ''}},\n       'cmd_txt': {'text': []},\n       'comment': '',\n       'fname': '',\n       'int_arg': -1,\n       'label_name': ''}}\n\u003e\u003e\u003e\n```\n\nUse `.to_json()` to convert a command into JSON.\n\n```python\n\u003e\u003e\u003e print(cmd_n.to_json())\n{\n    \"a1\": {\n        \"addr_type\": 7\n    },\n    \"addr_bang\": true,\n    \"cmd\": \"N\",\n    \"line\": 2\n}\n\u003e\u003e\u003e\n```\n\nHave fun!\n\n```python\n\u003e\u003e\u003e [x.cmd for x in parsed]  # list of commands\n['{', 'N', 's', '}']\n\u003e\u003e\u003e [str(x) for x in parsed if x.a1 is None]  # commands with no address\n['s/\\\\n/-/gi', '}']\n\u003e\u003e\u003e [str(x) for x in parsed if x.addr_bang]  # commands with bang !\n['$ !N']\n\u003e\u003e\u003e [x.x.comment for x in parsed if x.x.comment]  # extract all comments\n[]\n\u003e\u003e\u003e [x.x.fname for x in parsed if x.cmd in \"rRwW\"]  # list of read/write filenames\n[]\n\u003e\u003e\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faureliojargas%2Fsedparse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faureliojargas%2Fsedparse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faureliojargas%2Fsedparse/lists"}