在bash数组中存储JQ NULL分隔的输出

时间:2018-03-16 12:39:39

标签: bash jq nul

on bash 4.4.12使用jq 1.5和这个单行IFS=_ read -r -a a < <(jq -ncj '["a","b","c"][]+"_"') ; printf '%s\n' "${a[@]}"我得到一个正确分隔的输出

  

     

B'/ P>      

C

分别对于元素a,b和c,但是如果我尝试使用null定界符同样的事情:IFS= read -r -a a < <(jq -ncj '["a","b","c"][]+"\u0000"') ; printf '%s\n' "${a[@]}"那么我只得到一个包含

的数组元素
  

ABC

为什么这不能像预期的那样工作?

此外,如果您尝试IFS= read -r -d '' -a a < <(jq -ncj '["a","b","c"][]+"\u0000"') ; printf '%s\n' "${a[@]},您会惊讶地发现只有第一个“ a ”元素的数组:

  

我的目标是找到一种方法,而不用任何类型的循环迭代元素。

编辑:**readarray -d**不是解决方案,因为我需要在版本4.4之前的bash中运行该代码

3 个答案:

答案 0 :(得分:4)

使用readarray-dread bash中的$ readarray -d $'\0' -t a < <(jq -ncj '["a","b","c"][]+"\u0000"') $ declare -p a declare -a a=([0]="a" [1]="b" [2]="c") 类似-d ''获得''

readarray -d

while也适用;由于shell字符串是空终止的,因此read在技术上是包含空字符的字符串。

如果没有bash支持,您可以使用a=() while read -d '' -r item; do a+=("$item") done < <( jq -ncj '["a","b","c"][]+"\u0000"' ) 循环const navButtonsMsg = new BotBuilder.Message(session) .text("Hello") .suggestedActions( BotBuilder.SuggestedActions.create( session, [ BotBuilder.CardAction.imBack(session, "red", "red"), BotBuilder.CardAction.imBack(session, "blue", "blue"), BotBuilder.CardAction.imBack(session, "green", "green") ] ) ); session.send(navButtonsMsg); ,该循环适用于任何版本的const navButtonsMsg = new BotBuilder.Message(session) .suggestedActions( BotBuilder.SuggestedActions.create( session, [ BotBuilder.CardAction.imBack(session, "red", "red"), BotBuilder.CardAction.imBack(session, "blue", "blue"), BotBuilder.CardAction.imBack(session, "green", "green") ] ) ); session.send(navButtonsMsg);

data.table

这是你能做的最好的事情,除非你对数组元素有所了解,可以让你选择一个不属于任何元素的替代分隔符。

答案 1 :(得分:1)

我假设您要切换为使用空定界符而不是_,以提高脚本的可靠性。但是,读取json元素的最安全方法不是使用null分隔符,因为根据RFC7159(page 8)允许使用json文本。例如。如果["a","b","c"]看起来像["a","b\u0000","c"],而您要将空字符附加到每个字符串并使用空定界符来解析它们,则“ b”元素将进入两个单独的bash数组插槽。

相反,考虑到换行总是在json-strings中转义,例如jq -c我建议依靠规范中的

部分
  

“字符串以引号开头和结尾。”

考虑到这一点,我们可以定义:

jsonStripQuotes(){ local t0; while read -r t0; do t0="${t0%\"}"; t0="${t0#\"}"; printf '%s\n' "$t0"; done < <(jq '.');}

然后,例如

echo '["a\u0000 b\n","b\nnn","c d"]' | jq .[] | jsonStripQuotes

..应安全地将每个json字符串打印在单独的行上(附加扩展的换行符),并转义字符串中的所有换行符和null。之后,我将IFS设置为仅换行:

while IFS=$'\n' do read -r elem; Arr+=("$elem") ; done < <(echo '["a\u0000 b\n","b\nnn","c d"]' | jq .[] | stripJsonQuotes)

然后如果要用换行符等打印它们,请展开:

printf '%b' "${Arr[*]}"

我相信这是将json字符串解析为bash数组的最可靠方法。

答案 2 :(得分:0)

由于您没有使用jq&#39; $ readarray -t a < <(jq -nc '["a","b","c"][]') ; printf '%s\n' "${a[@]}" "a" "b" "c" 选项,因此问题是标题中提出的问题是否为"XY" problem。如果目标只是将JSON值分配给bash数组,请考虑:

$ readarray -t a < <(jq -nc '["a\\b","\"b\"","c"][]') ; printf '%s\n' "${a[@]}"
"a\\b"
"\"b\""
"c"

请注意,bash数组值是可识别的JSON值(在本例中为JSON字符串,带有双引号)。

更有说服力的是:<​​/ p>

$ readarray -d "" a < <(jq -ncj '["a\\b","\"b\"","c"][]+"\u0000"') ; printf '%s\n' "${a[@]}"
a\b
"b"
c

比较&#34; JSONarity&#34;当使用带有NUL的readarray时会发生这种情况:

angular.forEach($scope.emails, function(email){
 if(email.value ===""){
   $scope.emails.splice($scope.emails.indexOf(email), 1);
 } 

});