目录


项目简介

jq 是一个轻量级、灵活的命令行 JSON 处理器,类似于 sedawkgrep 等工具,但专门用于处理 JSON 数据。它使用可移植的 C 语言编写,零运行时依赖,可以轻松地切片、过滤、映射和转换结构化数据。

仓库地址: git@gitcode.com:nutpi/jq.git

版本: v1.7

Tag: 1.7_ohos


jq 是什么

jq 是一个命令行工具,用于处理 JSON 数据。它提供了强大的查询和转换功能,可以让你从 JSON 数据中提取、过滤、转换和格式化信息。

主要优势

  • 轻量级:使用 C 语言编写,零运行时依赖
  • 高性能:编译后是单个可执行文件,运行速度快
  • 功能强大:支持复杂的 JSON 查询和转换
  • 易于使用:简洁的语法,学习曲线平缓
  • 跨平台:支持 Windows、macOS、Linux 等平台

与 sed/awk 的对比

特性 sed/awk jq
数据类型 文本 JSON
语法 正则表达式 JSONPath 类似语法
类型安全
JSON 支持 需要手动解析 原生支持
性能 中等

jq 的主要特性

1. 数据提取

  • 提取 JSON 对象的字段
  • 提取数组元素
  • 嵌套数据访问
  • 条件过滤

2. 数据转换

  • 映射数组元素
  • 过滤数组
  • 排序和去重
  • 分组和聚合

3. 格式化输出

  • 美化 JSON 输出
  • 压缩 JSON 输出
  • 自定义输出格式
  • 颜色高亮(终端支持)

4. 流式处理

  • 处理大型 JSON 文件
  • 流式 JSON 解析
  • 增量处理

jq 的使用方法

基本用法

# 美化 JSON 输出
jq '.' file.json

# 提取字段
jq '.name' file.json

# 提取数组元素
jq '.[0]' file.json

# 过滤数组
jq '.[] | select(.age > 18)' file.json

# 映射数组
jq '.[] | .name' file.json

常用操作

数据提取
# 提取对象字段
jq '.user.name' data.json

# 提取多个字段
jq '{name: .name, age: .age}' data.json

# 提取数组元素
jq '.users[0]' data.json

# 提取数组的所有元素
jq '.users[]' data.json
数据过滤
# 条件过滤
jq '.[] | select(.age > 18)' users.json

# 多条件过滤
jq '.[] | select(.age > 18 and .active == true)' users.json

# 字符串匹配
jq '.[] | select(.name | contains("John"))' users.json
数据转换
# 映射数组
jq '[.[] | .name]' users.json

# 计算
jq '[.[] | {name: .name, double_age: .age * 2}]' users.json

# 分组
jq 'group_by(.department)' employees.json

# 排序
jq 'sort_by(.age)' users.json
格式化输出
# 美化输出(默认)
jq '.' file.json

# 压缩输出
jq -c '.' file.json

# 原始字符串(不转义)
jq -r '.name' file.json

# 自定义输出
jq -r '"\(.name) is \(.age) years old"' users.json

实际使用示例

# 从 package.json 提取版本号
jq -r '.version' package.json

# 列出所有依赖
jq '.dependencies | keys' package.json

# 过滤 GitHub API 响应
curl -s https://api.github.com/users/octocat | jq '{name: .name, bio: .bio, public_repos: .public_repos}'

# 处理多个 JSON 对象(流式)
cat *.json | jq -s '.[] | select(.status == "active")'

# 统计数组长度
jq '.users | length' data.json

# 查找最大值
jq '[.[] | .age] | max' users.json

# 数组去重
jq 'unique' array.json

# 合并多个 JSON 对象
jq -s 'add' file1.json file2.json

HarmonyOS 适配过程

项目特点

jq 使用 Autotools(autoconf、automake)作为构建系统,这是一个传统的 C 项目构建方式。与之前适配的 Rust 项目(exa、dog)不同,Autotools 项目需要特殊的配置和子模块处理。

适配挑战

  1. 构建系统差异:Autotools 需要 configure 脚本
  2. 子模块依赖:oniguruma 子模块需要特殊处理
  3. 交叉编译配置:需要正确配置目标平台和工具链
  4. config.h 生成:子模块的 config.h 生成问题
  5. 安装路径控制:需要正确设置 DESTDIR 和 prefix

环境准备

1. 系统要求

  • macOS(本文示例)或 Linux
  • Autotools(autoconf、automake、libtool)
  • HarmonyOS SDK
  • Python 3(用于构建脚本)
  • Git(用于子模块)

2. 安装 Autotools

# macOS (使用 Homebrew)
brew install autoconf automake libtool

# Linux (Ubuntu/Debian)
sudo apt-get install autoconf automake libtool

# Linux (CentOS/RHEL)
sudo yum install autoconf automake libtool

3. 验证工具

autoconf --version
automake --version
libtool --version

4. 环境变量设置

构建脚本会自动设置以下环境变量:

export CC=${COMPILER_TOOLCHAIN}clang
export CXX=${COMPILER_TOOLCHAIN}clang++
export AR=${COMPILER_TOOLCHAIN}llvm-ar
export RANLIB=${COMPILER_TOOLCHAIN}llvm-ranlib
export STRIP=${COMPILER_TOOLCHAIN}llvm-strip

构建脚本详解

build_ohos.sh 完整代码

export TREE_INSTALL_HNP_PATH=${HNP_PUBLIC_PATH}/jq.org/jq_1.7

# 创建安装目录
mkdir -p ${TREE_INSTALL_HNP_PATH}/usr/bin
mkdir -p ${TREE_INSTALL_HNP_PATH}/usr/share/man/man1

# 初始化 git submodule(oniguruma 是必需的)
if [ ! -d vendor/oniguruma ] || [ -z "$(ls -A vendor/oniguruma 2>/dev/null)" ]; then
    git submodule update --init --recursive vendor/oniguruma
fi

# 验证 oniguruma 是否存在必要的文件
if [ ! -f vendor/oniguruma/configure.ac ] && [ ! -f vendor/oniguruma/configure ]; then
    echo "Error: vendor/oniguruma does not contain configure files"
    exit 1
fi

# 清理之前的构建
make clean 2>/dev/null || true
rm -rf autom4te.cache config.cache config.status config.log Makefile

# 如果 oniguruma 的 configure 脚本不存在,需要先运行 autoreconf
if [ ! -f vendor/oniguruma/configure ]; then
    cd vendor/oniguruma
    autoreconf -i
    cd ../..
fi

# 如果主 configure 脚本不存在,需要运行 autoreconf
if [ ! -f configure ]; then
    autoreconf -i
fi

# 配置构建
CPP_VAR="${CC} -E"
./configure \
    --host=aarch64-linux-musl \
    --prefix=${TREE_INSTALL_HNP_PATH}/usr \
    CC="${CC}" \
    CFLAGS="${CFLAGS}" \
    CPP="${CPP_VAR}" \
    CXX="${CXX}" \
    CXXFLAGS="${CXXFLAGS}" \
    LDFLAGS="${LDFLAGS}" \
    --with-oniguruma=builtin \
    --disable-maintainer-mode \
    --enable-static \
    --disable-shared

# 确保 oniguruma 子目录也被正确配置
if [ -d vendor/oniguruma ] && [ ! -f vendor/oniguruma/src/config.h ]; then
    cd vendor/oniguruma
    make distclean 2>/dev/null || true
    rm -f src/config.h config.status config.cache config.log Makefile
    
    CPP_VAR_ONIG="${CC} -E"
    ./configure \
        --host=aarch64-linux-musl \
        CC="${CC}" \
        CFLAGS="${CFLAGS}" \
        CPP="${CPP_VAR_ONIG}" \
        LDFLAGS="${LDFLAGS}" \
        --enable-static \
        --disable-shared
    
    # 强制生成 config.h(处理 config.status 的问题)
    if [ -f config.status ]; then
        rm -f src/config.h src/config.h.stamp
        mkdir -p src
        ./config.status 2>&1 | grep -v "is unchanged" || true
        
        # 如果文件仍然不存在或为空,使用回退方法生成
        if [ ! -s src/config.h ]; then
            cat > src/config.h << 'EOFCONFIG'
/* src/config.h. Generated manually as fallback */
#ifndef ONIG_CONFIG_H
#define ONIG_CONFIG_H
/* 基本定义... */
#endif
EOFCONFIG
        fi
    fi
    cd ../..
fi

# 构建
make -j$(sysctl -n hw.ncpu 2>/dev/null || echo 4) VERBOSE=1

# 安装
export DESTDIR=${TREE_INSTALL_HNP_PATH}
export prefix=/usr
make install

# 复制 hnp.json 并打包
cp hnp.json ${TREE_INSTALL_HNP_PATH}/
pushd ${TREE_INSTALL_HNP_PATH}/../
    ${HNP_TOOL} pack -i ${TREE_INSTALL_HNP_PATH} -o ${ARCHIVE_PATH}/
    tar -zvcf ${ARCHIVE_PATH}/ohos_jq_1.7.tar.gz jq_1.7/
popd

脚本关键点解析

1. Git Submodule 初始化
if [ ! -d vendor/oniguruma ] || [ -z "$(ls -A vendor/oniguruma 2>/dev/null)" ]; then
    git submodule update --init --recursive vendor/oniguruma
fi

关键点

  • oniguruma 是 jq 的正则表达式库依赖
  • 必须初始化子模块才能构建
  • 检查目录是否存在且非空
2. Autoreconf 处理
# 主项目
if [ ! -f configure ]; then
    autoreconf -i
fi

# 子模块
if [ ! -f vendor/oniguruma/configure ]; then
    cd vendor/oniguruma
    autoreconf -i
    cd ../..
fi

关键点

  • 主项目和子模块都需要运行 autoreconf
  • autoreconf -i 会安装缺失的辅助文件
3. 目标平台配置
--host=aarch64-linux-musl

关键点

  • 使用 aarch64-linux-musl 而不是 aarch64-linux-ohos
  • config.sub 认识 musl 配置
  • HarmonyOS 使用 musl libc,所以这个配置是合适的
4. C 预处理器配置
CPP_VAR="${CC} -E"
CPP="${CPP_VAR}"

关键点

  • CPP 应该是 C 预处理器,使用 clang -E
  • 不能使用 clang++(C++ 编译器)

关键问题解决

问题 1:构建系统错误

错误信息

make: *** No rule to make target `clean'. Stop.
make: *** No targets specified and no makefile found. Stop.

原因:jq 使用 Autotools,需要先运行 configure 生成 Makefile。

解决方案

  1. 运行 autoreconf -i 生成 configure 脚本
  2. 运行 ./configure 配置构建
  3. 然后才能使用 make

问题 2:C 预处理器错误

错误信息

configure: error: C preprocessor "/path/to/clang++" fails sanity check

原因CPP 环境变量被设置为 clang++(C++ 编译器),但 configure 期望的是 C 预处理器。

解决方案:在 configure 调用中明确设置 CPP="${CC} -E"

问题 3:目标平台配置错误

错误信息

configure: error: Invalid configuration 'aarch64-linux-ohos': OS 'ohos' not recognized

原因config.sub 脚本不认识 ohos 操作系统。

解决方案:使用 aarch64-linux-musl 作为 host,编译器标志会确保使用正确的 HarmonyOS SDK。

问题 4:oniguruma 子模块问题

错误信息

make[2]: *** No rule to make target `all'. Stop.

原因vendor/oniguruma 目录为空,git submodule 未初始化。

解决方案

  1. 检查并初始化 git submodule
  2. 为 oniguruma 运行 autoreconf
  3. 配置 oniguruma 子目录

问题 5:config.h 生成问题

错误信息

fatal error: 'config.h' file not found
config.status: src/config.h is unchanged

原因config.status 错误地认为文件 “is unchanged”,但实际上文件不存在或为空。

解决方案

  1. 删除旧文件和空文件
  2. 运行 config.status 生成文件
  3. 如果失败,使用回退方法手动生成 config.h

问题 6:安装路径错误

错误信息

mkdir: /usr/local/lib: Permission denied

原因make install 尝试安装到系统目录,需要 root 权限。

解决方案:设置 DESTDIRprefix 环境变量,让安装到构建目录。


oniguruma 子模块问题

问题分析

jq 依赖 oniguruma 正则表达式库,它作为 git submodule 存在。在交叉编译时:

  1. 子模块可能未初始化:如果从 tarball 构建,子模块目录可能为空
  2. 子模块需要配置:oniguruma 也使用 Autotools,需要运行 configure
  3. config.h 位置特殊:oniguruma 的 config.hsrc/ 子目录中

解决方案

1. 子模块初始化
# 检查子模块是否存在且非空
if [ ! -d vendor/oniguruma ] || [ -z "$(ls -A vendor/oniguruma 2>/dev/null)" ]; then
    git submodule update --init --recursive vendor/oniguruma
fi
2. 子模块配置
# 为 oniguruma 运行 autoreconf
if [ ! -f vendor/oniguruma/configure ]; then
    cd vendor/oniguruma
    autoreconf -i
    cd ../..
fi

# 配置 oniguruma
cd vendor/oniguruma
./configure --host=aarch64-linux-musl ...
cd ../..
3. config.h 生成
# 强制生成 config.h
if [ ! -s src/config.h ]; then
    # 使用回退方法生成
    cat > src/config.h << 'EOF'
/* 基本定义 */
EOF
fi

config.h 生成问题

问题现象

config.status 报告:

config.status: src/config.h is unchanged

但实际检查:

ls src/config.h
# No such file or directory

问题原因

config.status 脚本在比较文件时,如果目标文件不存在或为空,可能会错误地认为文件 “is unchanged”。这是 Autotools 的一个已知问题。

解决方案

方法 1:强制删除并重新生成
rm -f src/config.h src/config.h.stamp
./config.status
方法 2:回退方法生成

如果 config.status 仍然失败,手动生成一个基本的 config.h

cat > src/config.h << 'EOF'
/* src/config.h. Generated manually as fallback */
#ifndef ONIG_CONFIG_H
#define ONIG_CONFIG_H

#define HAVE_ALLOCA_H 1
#define HAVE_ALLOCA 1
#define HAVE_DLFCN_H 1
/* ... 其他必要的定义 ... */

#endif /* ONIG_CONFIG_H */
EOF

验证

生成后验证文件是否存在且非空:

if [ ! -s src/config.h ]; then
    echo "Error: config.h is missing or empty"
    exit 1
fi

安装路径问题

问题分析

默认情况下,make install 会安装到 --prefix 指定的路径。如果 prefix/usr/usr/local,需要 root 权限。

解决方案

使用 DESTDIR 环境变量:

export DESTDIR=${TREE_INSTALL_HNP_PATH}
export prefix=/usr
make install

工作原理

  • DESTDIR 是安装的根目录
  • prefix 是相对于 DESTDIR 的路径
  • 最终安装路径 = ${DESTDIR}${prefix} = ${TREE_INSTALL_HNP_PATH}/usr

示例

  • 二进制文件:${TREE_INSTALL_HNP_PATH}/usr/bin/jq
  • 库文件:${TREE_INSTALL_HNP_PATH}/usr/lib/libjq.a
  • 手册页:${TREE_INSTALL_HNP_PATH}/usr/share/man/man1/jq.1

HNP 包配置

hnp.json

{
    "type":"hnp-config",
    "name":"jq",
    "version":"1.7",
    "install":{}
}

这是一个简单的 HNP 包配置,定义了包的基本信息。

安装目录结构

jq_1.7/
├── usr/
│   ├── bin/
│   │   └── jq              # 可执行文件
│   ├── lib/
│   │   └── libjq.a         # 静态库(如果构建)
│   └── share/
│       └── man/
│           └── man1/
│               └── jq.1    # 用户手册
└── hnp.json                 # HNP 包配置

构建结果

构建成功后,会生成以下文件:

  1. HNP 包jq.org_jq_1.7.hnp

    • HarmonyOS 原生包格式
    • 可以直接安装到 HarmonyOS 设备
  2. Tar 归档ohos_jq_1.7.tar.gz

    • 压缩的 tar 归档
    • 包含完整的安装目录结构

构建输出示例

==========================================
Build completed successfully!
==========================================
HNP Package: /path/to/archive/jq.org_jq_1.7.hnp
Tar Archive: /path/to/archive/ohos_jq_1.7.tar.gz
Installation Path: /path/to/data/service/hnp/jq.org/jq_1.7
==========================================

使用示例

在 HarmonyOS 上使用 jq

安装 HNP 包后,可以在 HarmonyOS 设备上使用 jq:

# 美化 JSON 输出
echo '{"name":"John","age":30}' | jq '.'

# 提取字段
echo '{"name":"John","age":30}' | jq '.name'

# 处理文件
jq '.users[] | select(.active == true)' users.json

# 数组操作
jq '[.[] | .name]' data.json

# 条件过滤
jq '.[] | select(.age > 18)' users.json

# 数据转换
jq '[.[] | {name: .name, double_age: .age * 2}]' users.json

实际应用场景

  1. API 响应处理

    curl -s https://api.example.com/data | jq '.results[] | {id: .id, name: .name}'
    
  2. 配置文件处理

    # 提取配置值
    jq -r '.database.host' config.json
    
    # 修改配置
    jq '.database.port = 5432' config.json > config.new.json
    
  3. 日志分析

    # 过滤错误日志
    cat app.log | jq 'select(.level == "error")'
    
    # 统计错误数量
    cat app.log | jq '[select(.level == "error")] | length'
    
  4. 数据转换

    # JSON 转 CSV
    jq -r '.[] | [.name, .age, .city] | @csv' users.json
    
    # 提取特定字段
    jq '[.[] | {name: .name, email: .email}]' users.json
    

总结

适配要点

  1. 构建系统识别:Autotools 项目需要 autoreconfconfigure
  2. 子模块处理:正确处理 git submodule 的初始化和配置
  3. 目标平台选择:使用 aarch64-linux-musl 而不是 aarch64-linux-ohos
  4. C 预处理器配置:使用 clang -E 而不是 clang++
  5. config.h 生成:处理 config.status 的问题,提供回退方案
  6. 安装路径控制:使用 DESTDIRprefix 正确安装

关键决策

  1. 使用 musl 配置config.sub 认识 musl,编译器标志确保使用 HarmonyOS SDK
  2. 手动配置子模块:确保 oniguruma 子目录也被正确配置
  3. 回退方法:如果 config.status 失败,手动生成 config.h

优势

  • 零运行时依赖:jq 编译后是单个可执行文件,部署简单
  • 高性能:C 语言编写,运行速度快
  • 功能强大:支持复杂的 JSON 查询和转换
  • 易于集成:可以轻松集成到脚本和工具链中

适用场景

  • API 响应处理
  • 配置文件解析和修改
  • 日志分析和过滤
  • 数据转换和格式化
  • 脚本自动化
  • 数据管道处理

FAQ

Q1: 为什么选择 aarch64-linux-musl 作为目标平台?

A: config.sub 脚本不认识 aarch64-linux-ohos,但认识 aarch64-linux-musl。HarmonyOS 使用 musl libc,所以这个配置是合适的。编译器标志(--target=aarch64-linux-ohos--sysroot)会确保使用正确的 HarmonyOS SDK。

Q2: 为什么需要手动配置 oniguruma 子目录?

A: AC_CONFIG_SUBDIRS 应该会自动配置子目录,但有时会失败。手动配置可以确保子目录被正确配置,特别是 config.h 的生成。

Q3: config.h 生成失败怎么办?

A: 构建脚本提供了回退方法。如果 config.status 失败,会手动生成一个基本的 config.h 文件,包含必要的定义,足以让编译继续进行。

Q4: 如何验证构建的二进制文件?

A: 可以使用 file 命令检查:

file jq

应该显示类似:ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), ...

Q5: 构建失败怎么办?

A: 检查以下几点:

  1. Autotools 是否正确安装
  2. Git submodule 是否正确初始化
  3. HarmonyOS SDK 路径是否正确
  4. 环境变量是否正确设置
  5. config.h 是否成功生成

Q6: 可以在其他架构上构建吗?

A: 当前配置针对 aarch64 架构。如果需要支持其他架构(如 x86_64),需要修改目标平台和相应的工具链配置。

Q7: oniguruma 是必需的吗?

A: 是的,oniguruma 是 jq 的正则表达式库依赖,必须构建。使用 --with-oniguruma=builtin 选项会使用内置的 oniguruma。

Q8: 如何更新 SDK 路径?

A: SDK 路径通过 --sdk 参数传递给主构建脚本,会自动设置到环境变量中。构建脚本会使用这些环境变量。


相关链接

  • jq 官方网站:https://jqlang.org/
  • jq 在线试用:https://play.jqlang.org/
  • jq GitHub 仓库:https://github.com/jqlang/jq
  • HarmonyOS 适配仓库:https://gitcode.com/nutpi/jq
  • oniguruma 项目:https://github.com/kkos/oniguruma
  • Autotools 文档:https://www.gnu.org/software/automake/manual/
  • HarmonyOS 开发者文档:https://developer.harmonyos.com/
  • PC代码仓
  • PC社区
Logo

赋能鸿蒙PC开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐