【问题标题】:Passing key and values to external command from jq从 jq 将键和值传递给外部命令
【发布时间】:2018-02-28 16:44:22
【问题描述】:

我正在尝试做的事情:

使用 jq 在 bash 脚本中将参数传递给 ffmpeg。 在我定期生成的这个外部文件中有一个 JSON。

{
   "streams":[
      {
         "track":"/var/www/html/stream1.m3u8",
         "link":"http://playertest.longtailvideo.com/adaptive/bipbop/bipbop.m3u8"
      },
      {
         "track":"/var/www/html/stream2.m3u8",
         "link":"https://mnmedias.api.telequebec.tv/m3u8/29880.m3u8"
      },
      {
         "track":"/var/www/html/stream3.m3u8",
         "link":"http://www.streambox.fr/playlists/test_001/stream.m3u8"
      }
   ]
}

这是我根据https://github.com/stedolan/jq/issues/503 此处找到的响应尝试的命令

jq -r '.streams[] | ffmpeg -v verbose -i  \(.link | @sh) -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 \(.Track | @sh)"' streams.json | sh

但是我收到此错误消息:

jq: error: syntax error, unexpected IDENT, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
.streams[] | ffmpeg -v verbose -i  \(.link | @sh) -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 \(.Track | @sh)"                       
jq: 1 compile error

【问题讨论】:

  • 当然我猜。盒子上也安装了nodejs。

标签: json shell jq


【解决方案1】:

对原始代码的最短更改就是添加缺少的引号:

jq -r '.streams[] | "ffmpeg -v verbose -i  \(.link | @sh) -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 \(.Track | @sh)"' streams.json | sh
#                   ^-- this was missing

注意"ffmpeg ..." 是一个字符串,并且包含在引号中。也就是说,您依靠jq 为您的shell 生成安全代码——因为它具有为此目的明确构建的功能,所以这并不像其他想法那样糟糕;但最好还是尽可能避免代码生成。


作为一种避免代码生成并且对所有可能的文件名都安全的替代方法,使用 jq 生成以 NUL 分隔的轨道/链接对流,并使用 BashFAQ #1 循环来迭代它们:

#!/usr/bin/env bash

while IFS= read -r -d '' track && IFS= read -r -d '' link; do
  ffmpeg -v verbose -i "$link" -c copy -flags -global_header -hls_time 10 \
         -hls_list_size 6 -hls_wrap 10 -start_number 1 "$track" 
done < <(jq -j '.streams[] | ( .track + "\u0000" + .link + "\u0000" )' streams.json) 

【讨论】:

  • 谢谢大家!是的,最终使用了这个解决方案。尽管我可以完全控制输入(json 文件中的 url),但最好还是注意安全并小心输入。
【解决方案2】:

使用

#!/bin/bash

file="$1"
c=0
while true; do
    track=$(jq -r ".streams[$c].track" "$file" 2>/dev/null)
    link=$(jq -r ".streams[$c].link" "$file" 2>/dev/null)
    [[ ! $stream || ! $link ]] && break
    ffmpeg -v verbose -i "$link" -c copy -flags -global_header -hls_time 10 \
        -hls_list_size 6 -hls_wrap 10 -start_number 1 "$track" 
    ((c++))
done

用法:

./script.bash file.json

【讨论】:

  • 我不知道为什么有人会否决这个 - 这是正确且安全的代码。
【解决方案3】:

使用 生成 命令:

(将file.json替换为您自己的路径/文件)

#!/bin/bash

node<<EOF
var j=$(<file.json);
for (var i = 0; i<j.streams.length; i++) {
   console.log("ffmpeg -v verbose -i '" + j.streams[i].link + "' -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 '" + j.streams[i].track + "'");
}
EOF

输出:

ffmpeg -v verbose -i 'http://playertest.longtailvideo.com/adaptive/bipbop/bipbop.m3u8' -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 '/var/www/html/stream1.m3u8'
ffmpeg -v verbose -i 'https://mnmedias.api.telequebec.tv/m3u8/29880.m3u8' -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 '/var/www/html/stream2.m3u8'
ffmpeg -v verbose -i 'http://www.streambox.fr/playlists/test_001/stream.m3u8' -c copy -flags -global_header -hls_time 10 -hls_list_size 6 -hls_wrap 10 -start_number 1 '/var/www/html/stream3.m3u8'

【讨论】:

  • 如果你不控制文件名会很危险。如果有人创建http://example.com/bobby/$(rm -rf ~)/tables.m3u8...
  • 你有一个确切的想法/例子,说明使用这个真的很危险吗?
  • ...我在这里假设 OP 从他们无法控制的网站或 API 获取此 JSON。信任来自您无法控制的来源的内容来运行任意 shell 命令是一个坏主意。
  • (这也有点冒险,因为它将file.json 的内容作为 node.js 中的代码执行;如果有人知道您将使用他们给您下载的文件来执行此操作-- 或者正在进行中间人攻击,并想尝试替换内容以查看他们能逃脱什么 -- 他们可以放置更多恶意内容,而不是格式良好的 JSON 文档)。
  • 经过编辑,用于攻击此问题的 URL 需要更像 http://example.com/bobby/$(rm -rf ~)'$(rm -rf ~)'/tables.m3u3 以涵盖包含文字单引号和不包含文字单引号的情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-08-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多