最直接、最可靠的方法是 通过 shell 脚本调用 jq,并在 jq 中执行 shell 命令。

(图片来源网络,侵删)
核心思路
- JSON 输入: 你需要一个包含要检查的文件路径的 JSON 文件,这使得
jq可以批量处理多个文件。 jq的--arg或--argsfile: 将 JSON 文件中的路径传递给jq脚本。jq的builtins函数:jq有一个强大的内置函数叫做builtins,它返回一个包含所有可用函数的数组,我们可以利用它来检测是否存在os_exec函数。注意:os_exec并非在所有jq版本中都默认启用,它通常需要oniguruma正则库支持,或者需要编译时开启。os_exec不可用,下面的方法会失败。os_exec函数: 这是关键。os_exec("command")会在 shell 中执行指定的command,并返回命令的输出。- Shell 命令
test -f: 我们将使用test -f <filename>这个 shell 命令,如果文件存在且是普通文件,它会返回退出码 0;否则返回非 0。os_exec会捕获这个退出码作为其返回值(true对应 0,false对应非 0)。 jq输出:jq脚本将接收这个true或false值,并将其构造成一个新的、包含文件存在状态的 JSON 对象输出。
详细步骤与示例
准备输入文件
创建一个名为 files_to_check.json 的文件,内容如下:
{
"files": [
"/etc/hosts",
"/non_existent_file_12345.txt",
"/var/log/syslog",
"/dev/null"
]
}
编写 jq 脚本
创建一个名为 check_files.jq 的文件,这是核心逻辑。
# 定义一个函数来检查单个文件是否存在
# 输入: 文件路径 (字符串)
# 输出: true (如果存在) 或 false (如果不存在)
def file_exists($path):
# 使用 shell 的 "test -f" 命令
# os_exec 会执行命令并返回其退出码 (true=0, false!=0)
os_exec("test -f " + $path);
# 主程序开始
# 首先检查 os_exec 是否可用,这是一个健壮的做法
if (builtins | contains(["os_exec"])) then
# 从输入的 JSON 中获取文件列表
.files[] as $file_path |
{
"path": $file_path,
"exists": file_exists($file_path)
}
else
# os_exec 不可用,输出错误信息并停止
error("此脚本需要支持 'os_exec' 函数的 'jq' 版本,请尝试安装 'jq-onig' 或类似版本。")
end
脚本解释:
def file_exists($path): 定义了一个可复用的函数file_exists,它接收一个路径参数$path。os_exec("test -f " + $path): 这是执行检查的核心,它会拼接成test -f /etc/hosts这样的命令并执行。os_exec的返回值就是该命令的执行结果。.files[] as $file_path | ...: 这是jq的标准用法,它会遍历files数组中的每一个元素,并将其暂存到变量$file_path中。{ "path": ..., "exists": ... }: 为每个文件路径创建一个新的 JSON 对象,包含原始路径和检查结果。if (builtins | contains(["os_exec"])) then ... else ... end: 这是一个重要的健壮性检查,如果当前jq版本不支持os_exec,它会直接报错并退出,而不是执行一个无效的脚本。
执行命令
打开你的终端,运行以下命令:

(图片来源网络,侵删)
# -r (--raw-output) 可以让输出更整洁,但这里我们保留 JSON 格式,所以可以不加 # --argjson ftc files_to_check.json 将 JSON 文件内容作为变量 ftc 传递给 jq # -f check_files.jq 指定要执行的 jq 脚本 jq --argjson ftc files_to_check.json -f check_files.jq files_to_check.json
命令解释:
--argjson ftc files_to_check.json: 这会读取files_to_check.json文件的内容,并将其作为一个 JSON 对象赋值给jq内部的变量ftc,在脚本中,我们通过ftc.files来访问它。-f check_files.jq: 指定要执行的jq脚本文件。- 最后的
files_to_check.json是jq的输入源,虽然我们通过--argjson已经传入了数据,但jq仍然需要一个输入流,在这种情况下,我们再次将同一个文件作为输入,这是最简单的方式。
预期输出
你会得到类似下面的结果:
{
"path": "/etc/hosts",
"exists": true
}
{
"path": "/non_existent_file_12345.txt",
"exists": false
}
{
"path": "/var/log/syslog",
"exists": true
}
{
"path": "/dev/null",
"exists": true
}
重要注意事项与替代方案
os_exec 的可用性问题
如前所述,os_exec 并非所有 jq 版本都有,你可以通过以下命令检查你的 jq 是否支持它:
# 输出应包含 "os_exec" jq -n 'builtins'
如果你的 jq 不支持 os_exec,你有几个选择:

(图片来源网络,侵删)
-
安装支持
os_exec的版本:- 在基于 Debian/Ubuntu 的系统上:
sudo apt-get install jq-onig - 在 macOS 上 (使用 Homebrew):
brew install jq-oniguruma - 从源码编译时,确保启用了
oniguruma选项。
- 在基于 Debian/Ubuntu 的系统上:
-
使用
sh命令 (更通用的 shell 脚本方法): 这不是纯jq的解决方案,但在实际应用中更常见、更可靠,你可以在 shell 脚本中循环调用jq,或者让jq输出 shell 命令,然后由sh执行。示例:Shell 脚本 +
jqcheck_files.sh:#!/bin/bash # 1. 使用 jq 提取所有文件路径到一个数组 # -r 输出原始字符串,方便 shell 处理 mapfile -t files_to_check < <(jq -r '.files[]' files_to_check.json) # 2. 遍历数组并检查每个文件 for path in "${files_to_check[@]}"; do # 使用标准的 shell test 命令 if [ -f "$path" ]; then echo "文件存在: $path" else echo "文件不存在: $path" fi done这种方法更符合 shell 脚本的编程范式,不依赖于
jq的高级特性。
安全性 (os_exec 的风险)
os_exec 会执行任意 shell 命令,如果输入的 JSON 文件来源不可信(例如来自用户上传),攻击者可能注入恶意命令,如果 JSON 中有一个路径是 "; rm -rf / #", os_exec 可能会变成 test -f "; rm -rf / #",这非常危险。
如果你必须处理不可信的输入,请务必进行清理或使用更安全的方法(如上面的纯 shell 脚本方法)。
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
jq + os_exec |
代码逻辑集中在 jq 脚本中,适合处理 JSON 数据流。 |
依赖特定 jq 版本;有命令注入风险。 |
处理可信的、结构化的 JSON 输入,且环境支持 os_exec。 |
Shell 脚本 + jq |
通用、可靠、安全;不依赖 jq 的高级特性。 |
逻辑分散在 shell 和 jq 之间。 |
推荐使用,绝大多数生产环境和自动化脚本场景。 |
对于大多数用户来说,第二种方法(Shell 脚本调用 jq)是更实用、更安全的选择,但如果你正在构建一个纯 jq 的数据处理管道,并且环境可控,第一种方法则非常优雅。
