开发工具【免费下载链接】jcCLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.项目地址https://gitcode.com/gh_mirrors/jc/jc点击查看免费下载本文以 jc 项目中的jar_manifest解析器为主线讲解如何把 Java 应用程序打包生成的MANIFEST.MF清单文件以及unzip -c批量解压输出的多归档内容一键转换为结构化 JSON从而摆脱手写正则直接配合jq做版本核查、依赖审计与自动化脚本。读完本文你将掌握 CLI 与 Python 模块两种调用方式、输出 Schema 与字段命名规则以及该解析器处理多行折行属性和多 JAR 归档的底层实现原理。一、MANIFEST.MF 是什么为什么需要解析器MANIFEST.MF是 Java 归档JAR中META-INF/目录下的清单文件采用Key: Value的文本行格式记录了 JAR 包的元数据。在 OSGi、Spring Boot、Apache Log4j 等生态中它承载了大量关键信息Manifest-Version清单文件格式版本Bundle-SymbolicName/Bundle-Version/Bundle-LicenseOSGi 插件的符号名、版本与许可证Import-Package/Export-Package包的依赖导入与导出声明含版本区间与resolution:optional标记Built-By/Created-By/Build-Jdk/Tool构建者、构建工具与 JDK 版本Implementation-Version/Implementation-Title/Implementation-Vendor实现版本与厂商信息。正是这些属性让安全审计如核对 Log4j 2.16.0/2.17.0 等版本、依赖清单核查和 CI 发布验证有了可靠依据。但原始MANIFEST.MF有两大解析痛点行长度限制JAR 规范要求单行不超过 72 字节超长的值尤其是Import-Package、Export-Package必须折行书写续行以单个空格开头读取时需要把续行拼接回所属键键名不规整键名包含连字符Bundle-License、Bnd-LastModified等且大小写混杂直接在脚本中当字段名使用容易出错。jc 的jar_manifest解析器jc/parsers/jar_manifest.py正是为这两个场景而生它把整个清单内容解析成由字典组成的列表并对键名做统一规范化处理。二、快速上手CLI 与 Python 模块两种用法根据官方文档docs/parsers/jar_manifest.mdjar_manifest支持命令行管道与 Python 库两种调用方式。2.1 CLI 管道用法# 直接解析一个 MANIFEST.MF 文件 $ cat MANIFEST.MF | jc --jar-manifest # 解析单个 JAR 内部的清单文件-p 表示 pretty 输出 $ unzip -c log4j-core-2.16.0.jar META-INF/MANIFEST.MF | \ jc --jar-manifest -p # 批量解析多个 JAR 的清单文件注意通配符需要加引号 $ unzip -c apache-log4j-2.16.0-bin/*.jar META-INF/MANIFEST.MF | \ jc --jar-manifest -p命令行选项--jar-manifest已在 bash/zsh 补全脚本中注册见 completions/jc_bash_completion.sh 与 completions/jc_zsh_completion.shREADME.md的解析器一览表中也有对应条目。-p选项用于输出缩进美化后的 JSON便于人眼阅读。2.2 Python 模块用法import jc # jar_manifest_file_output 为 MANIFEST.MF 的文本内容str result jc.parse(jar_manifest, jar_manifest_file_output)返回值为List[Dict]每个字典对应一份清单。解析器模块内可直接导入调用import jc.parsers.jar_manifest result jc.parsers.jar_manifest.parse(text, quietTrue)parse()是模块的主解析函数签名与参数语义在源码 docstring 中有完整说明jc/parsers/jar_manifest.py参数类型说明datastring待解析的文本数据rawboolean为True时返回未处理的原始输出quietboolean为True时抑制兼容性警告信息返回值List of Dictionaries即原始或加工后的结构化数据。parse()内部会先调用jc.utils.compatibility()做平台兼容性检查再调用jc.utils.input_type_check()校验输入必须是字符串非字符串会抛出TypeError空输入无任何非空白字符则直接返回空列表[]——这些行为在 jc/utils.py 中均有实现。2.3 输出 Schema[ { key1: string, key2: string } ]顶层是数组每个元素是一个字典字典的键来自清单中的属性名值均为字符串。三、实测输出与字段命名规则以 Log4j 的清单文件为例文档示例实际 fixture 见 tests/fixtures/rhel-8/MANIFEST.MF.out$ cat MANIFEST.MF | jc --jar-manifest -p[ { Import_Package: com.conversantmedia.util.concurrent;resoluti..., Export_Package: org.apache.logging.log4j.core;uses:\org.ap..., Manifest_Version: 1.0, Bundle_License: https://www.apache.org/licenses/LICENSE-2.0.txt, Bundle_SymbolicName: org.apache.logging.log4j.core, Built_By: matt, Bnd_LastModified: 1639373735804, Implementation_Vendor_Id: org.apache.logging.log4j, Specification_Title: Apache Log4j Core, Log4jReleaseManager: Matt Sicker, ... } ]从输出可以归纳出解析器的字段命名规范化规则由源码parse()收尾处的处理逻辑实现见 jc/parsers/jar_manifest.py键名中的所有空白字符被移除re.sub(r\s, , k)键名中的所有连字符-被替换为下划线_re.sub(r-, _, k)。因此Manifest-Version→Manifest_VersionBundle-License→Bundle_LicenseBnd-LastModified→Bnd_LastModifiedImplementation-Vendor-Id→Implementation_Vendor_IdBuild-Jdk→Build_JdkX-Compile-Target-JDK→X_Compile_Target_JDK。所有值统一为字符串例如Manifest_Version: 1.0、Multi_Release: true、Bnd_LastModified: 1639792304782毫秒时间戳仍以字符串保留。完整键值对照可参考测试期望输出 tests/fixtures/rhel-8/MANIFEST.MF.json。四、批量 JAR 场景多归档清单一次解析文档重点展示的第二种用法是配合unzip -c的通配符批量模式将多个 JAR 的清单一次性喂给解析器$ unzip -c apache-log4j-2.16.0-bin/*.jar META-INF/MANIFEST.MF | \ jc --jar-manifest -p此时输出不再是单个字典而是数组中的多个字典每个字典代表一个 JAR 的清单。文档示例输出如下[ ... { Archive: apache-log4j-2.16.0-bin/log4j-spring-boot-2.16.0-so..., Manifest_Version: 1.0, Built_By: matt, Created_By: Apache Maven 3.8.4, Build_Jdk: 1.8.0_312 }, { Archive: apache-log4j-2.16.0-bin/log4j-spring-boot-2.16.0-ja..., Manifest_Version: 1.0, Built_By: matt, Created_By: Apache Maven 3.8.4, Build_Jdk: 1.8.0_312 }, { Bundle_SymbolicName: org.apache.logging.log4j.spring-cloud-c..., Export_Package: org.apache.logging.log4j.spring.cloud.config..., Archive: apache-log4j-2.16.0-bin/log4j-spring-cloud-config-c..., Manifest_Version: 1.0, Bundle_License: https://www.apache.org/licenses/LICENSE-2.0.txt, ... } ... ]可以看到批量模式下每个字典额外携带了一个Archive字段其值来自unzip -c输出中每段归档开始处的Archive: 文件名行观察真实输入 tests/fixtures/rhel-8/MANIFEST.MF.MULTI.out 可以看到每个归档段以Archive: log4j-api-2.17.0.jar、inflating: META-INF/MANIFEST.MF等行开头。这让后续可以精确回溯每条元数据来自哪个 JAR 文件对批量审计非常有价值。对应的测试期望输出在 tests/fixtures/rhel-8/MANIFEST.MF.MULTI.json测试用例见 tests/test_jar_manifest.py。五、解析原理源码级拆解5.1 预处理去掉噪音行按归档分段parse()拿到文本后jc/parsers/jar_manifest.py依次做三件事若最后一行以archives were successfully processed.结尾说明是unzip -c的批量输出删掉这行统计信息以空行为分隔符把整个输出切成若干段每段对应一个归档若最后一段非空也会补入列表逐段处理先剔除以inflating: META-INF/MANIFEST.MF开头的行大小写不敏感因为它只是 unzip 的解压提示不是清单内容。5.2 核心难点多行折行属性的拼接JAR 规范允许长值折行续行以空格开头。源码对每段逐行扫描jc/parsers/jar_manifest.py遇到以空白开头的行判定为某个键的续行把上一行含键名行与续行内容直接拼接并移除所有空白字符re.sub(r\s, , v)若紧接着的下一行不是以空白开头即\S匹配说明该多行属性已结束把拼好的键值对存入结果处理完所有续行后从行列表中弹出这些被合并的行剩下的普通Key: Value行统一用split(:, maxsplit1)切分maxsplit1保证值中即使含冒号如 URL、版本区间中的;与:也不会被误拆。以 fixture 中真实的Import-Package为例其值长达数百字节在文件里被拆成约 70 行每行首字母小写且以空格续行如al,com.fasterxml...、tional,...解析后拼接恢复为完整的一整串依赖声明并在tests/fixtures/rhel-8/MANIFEST.MF.json中对应为单行字符串。这就是为什么输出中的Import_Package/Export_Package值看起来又长又完整。5.3 收尾键名规范化与字段归并每个字典无论是折行属性还是普通键值对先按单键字典收集最后统一合并进一个大字典同时完成 5.1 节所述的“去空白、连字符转下划线”规范化jc/parsers/jar_manifest.py。rawTrue时直接返回原始解析结果否则经过_process()该解析器当前版本中直接原样返回输出。整个模块的元数据版本 0.01、作者 Matt J、兼容平台linux, darwin, cygwin, win32, aix, freebsd、标签file定义在info类中jc/parsers/jar_manifest.py。5.4 测试验证仓库为解析器提供了三组单元测试tests/test_jar_manifest.py空数据输入返回[]单归档输入与期望 JSON 完全一致MANIFEST.MF.out↔MANIFEST.MF.json多归档输入与期望 JSON 完全一致MANIFEST.MF.MULTI.out↔MANIFEST.MF.MULTI.json。这组测试同时验证了折行拼接、多归档分段和键名规范化三处核心逻辑。六、实战把解析结果接到 jq 与自动化流程由于输出是标准 JSON 数组可以无缝接入jq。以下是几个可直接落地的用法# 批量解析后列出所有 JAR 的版本与 Bundle 符号名 $ unzip -c apache-log4j-2.16.0-bin/*.jar META-INF/MANIFEST.MF | \ jc --jar-manifest -p | \ jq -r .[] | [.Archive, .Bundle_SymbolicName, .Bundle_Version] | tsv # 找出所有包含特定依赖包如 org.zeromq的清单 $ cat MANIFEST.MF | jc --jar-manifest | \ jq -r .[0].Import_Package | select(contains(org.zeromq)) # 在 Python 中做版本审计 import jc mf jc.parse(jar_manifest, open(MANIFEST.MF).read()) print(mf[0][Implementation_Version]) # 例如 2.17.0结合Import_Package/Export_Package的完整拼接值可以进一步实现 OSGi 依赖解析、版本区间如[2.12,3)校验等高级审计逻辑将原本繁琐的文本解析工作沉淀为可复用的脚本。七、使用注意事项输入必须是字符串parse()对非字符串输入会抛出TypeError见 jc/utils.py 的input_type_check从文件读取时请用open(...).read()显式转为文本平台兼容性解析器声明兼容linux, darwin, cygwin, win32, aix, freebsd在不兼容平台且未设置quietTrue时会向 STDERR 输出警告行为由 jc/utils.py 的compatibility()控制空输入返回空列表无数据的输入返回[]而非报错值类型全部为字符串时间戳、版本号、布尔值true均按字符串保留类型转换需自行处理依赖 unzip 输出约定批量模式依赖unzip -c的Archive:头与空行分段格式若使用其他工具提取清单文本需保证结构与此一致。以上即为基于 docs/parsers/jar_manifest.md 与仓库源码、测试、fixture 编写的完整技术文章核心命令、Schema、命名规则、多归档示例均已完整继承并做了源码级扩展。赞分享开发工具【免费下载链接】jcCLI tool and python library that converts the output of popular command-line tools, file-types, and common strings to JSON, YAML, or Dictionaries. This allows piping of output to tools like jq and simplifying automation scripts.项目地址https://gitcode.com/gh_mirrors/jc/jc点击查看免费下载相关推荐jc解析器开发自定义解析器编写指南jc解析器开发自定义解析器编写指南 jc是一个功能强大的命令行工具能够将各种Unix命令输出、文件格式和字符串转换为JSON数据结构。本文详细介绍了jc解析开发工具使用 gTTS 将文本转换为语音python-mini-projects 之 Text_to_speech 实战解析使用 gTTS 将文本转换为语音python mini projects 之 Text_to_speech 实战解析 本文以 python mini proj示例工程Apache DolphinScheduler 子流程节点SubProcess使用指南将工作流作为节点复用的实战解析Apache DolphinScheduler 子流程节点SubProcess使用指南将工作流作为节点复用的实战解析 子流程SubProcess节点是任务调度大数据后端前端上一篇突破256K上下文壁垒Qwen3-VL-30B-A3B-Instruct长文档与视频理解技术揭秘下一篇微前端灾难防护qiankun错误边界设计全解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
