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

jq 网页代码检查本地文件是否存在
(图片来源网络,侵删)

核心思路

  1. JSON 输入: 你需要一个包含要检查的文件路径的 JSON 文件,这使得 jq 可以批量处理多个文件。
  2. jq--arg--argsfile: 将 JSON 文件中的路径传递给 jq 脚本。
  3. jqbuiltins 函数: jq 有一个强大的内置函数叫做 builtins,它返回一个包含所有可用函数的数组,我们可以利用它来检测是否存在 os_exec 函数。注意:os_exec 并非在所有 jq 版本中都默认启用,它通常需要 oniguruma 正则库支持,或者需要编译时开启。os_exec 不可用,下面的方法会失败。
  4. os_exec 函数: 这是关键。os_exec("command") 会在 shell 中执行指定的 command,并返回命令的输出。
  5. Shell 命令 test -f: 我们将使用 test -f <filename> 这个 shell 命令,如果文件存在且是普通文件,它会返回退出码 0;否则返回非 0。os_exec 会捕获这个退出码作为其返回值(true 对应 0,false 对应非 0)。
  6. jq 输出: jq 脚本将接收这个 truefalse 值,并将其构造成一个新的、包含文件存在状态的 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,它会直接报错并退出,而不是执行一个无效的脚本。

执行命令

打开你的终端,运行以下命令:

jq 网页代码检查本地文件是否存在
(图片来源网络,侵删)
# -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.jsonjq 的输入源,虽然我们通过 --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,你有几个选择:

jq 网页代码检查本地文件是否存在
(图片来源网络,侵删)
  • 安装支持 os_exec 的版本:

    • 在基于 Debian/Ubuntu 的系统上:sudo apt-get install jq-onig
    • 在 macOS 上 (使用 Homebrew): brew install jq-oniguruma
    • 从源码编译时,确保启用了 oniguruma 选项。
  • 使用 sh 命令 (更通用的 shell 脚本方法): 这不是纯 jq 的解决方案,但在实际应用中更常见、更可靠,你可以在 shell 脚本中循环调用 jq,或者让 jq 输出 shell 命令,然后由 sh 执行。

    示例:Shell 脚本 + jq

    check_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 的数据处理管道,并且环境可控,第一种方法则非常优雅。