【问题标题】:update json with jq through shell script通过shell脚本用jq更新json
【发布时间】:2017-02-17 11:16:38
【问题描述】:

我创建了一个 shell 脚本来使用 jq 创建和更新 json 文件。创建 json 文件运行良好。我有一个变量作为参数传递给 jq 命令

#!/bin/sh
OPER=$1
FILE_PATH=$2
DATE_TIME=`date +%Y-%m-%d:%H:%M:%S`
DATE=`date +%Y-%m-%d`
CSV=$3
STEP=$4
STATUS=$5
CODE=$6
MESSAGE=$7

if [ "$#" -eq 7 ]; then
    if [ "$OPER" == "create" ]; then
        # echo "FILE_PATH: $FILE_PATH - CSV: $CSV - STEP: $STEP - STATUS: $STATUS - CODE: $CODE - MESSAGE: $MESSAGE"
        REPORT="{\"date\": \"$DATE\", \"csv\": \"$CSV\", \"messages\": [{ \"timestamp\": \"$DATE_TIME\", \"step\": \"$STEP\", \"status\": \"$STATUS\", \"code\": \"$CODE\", \"message\": \"$MESSAGE\" }] }"
        echo ${REPORT} | jq . > $FILE_PATH
    elif [ "$OPER" == "update" ]; then
                echo "FILE_PATH: $FILE_PATH - CSV: $CSV - STEP: $STEP - STATUS: $STATUS - CODE: $CODE - MESSAGE: $MESSAGE"
        REPORT="{\"timestamp\": \"$DATE_TIME\", \"step\": \"$STEP\", \"status\": \"$STATUS\", \"code\": \"$CODE\", \"message\": \"$MESSAGE\"}"
        echo "REPORTTTTT: "$REPORT
        REPORT="jq '.messages[.messages| length] |= . + $REPORT' $FILE_PATH"
        #echo $REPORT
        echo `jq '.messages[.messages| length] |= . + $REPORT' $FILE_PATH` > $FILE_PATH
    else
        echo "operation not recognized: $OPER"
    fi
else
        echo "wrong parameters."
fi
jq . $FILE_PATH

但是要更新 json 文件,我遇到了错误。我的 $REPORT 变量是正确的。科特斯是正确的。我想我必须使用另一个 jq 参数而不是 |= . +。我将该命令与纯文本一起使用,并且有效。但是当我动态创建 REPORT 变量时,它会引发错误。

有什么线索吗?谢谢

REPORTTTTT: {"timestamp": "2017-02-17:12:11:11", "step": "2", "status": "OK", "code": "34", "message": "message 34 file.xml"}
jq: error: syntax error, unexpected INVALID_CHARACTER, expecting $end (Unix shell quoting issues?) at <top-level>, line 1:
'.messages[.messages|
jq: 1 compile error

jq: error: REPORT/0 is not defined at <top-level>, line 1:
.messages[.messages| length] |= . + $REPORT                                    
jq: 1 compile error

这是命令行中的示例>>

$ jq . file.json 
{
  "date": "2017-02-17",
  "csv": "file.csv",
  "messages": [
    {
      "timestamp": "2017-02-17:12:31:21",
      "step": "1",
      "status": "OK",
      "code": "33",
      "message": "message 33"
    }
  ]
}
$ export REPORT="{\"timestamp\": \"2017-02-17:11:51:14\", \"step\": \"2\", \"status\": \"OK\", \"code\": \"34\", \"message\": \"message 34 file.xml\"}"
$ echo $REPORT
{"timestamp": "2017-02-17:11:51:14", "step": "2", "status": "OK", "code": "34", "message": "message 34 file.xml"}
$ jq '.messages[.messages| length] |= . + $REPORT' file.json 
jq: error: REPORT/0 is not defined at <top-level>, line 1:
.messages[.messages| length] |= . + $REPORT                                    
jq: 1 compile error

【问题讨论】:

标签: json bash shell sh jq


【解决方案1】:

使用从jq-1.5 开始支持的--argjson 标志将$REPORT 参数作为json 参数传递,

--argjson name JSON-text:    
This option passes a JSON-encoded value to the jq program as a predefined variable. 

将你的线路改为,

jq --argjson args "$REPORT" '.data.messages += [$args]' file

【讨论】:

    【解决方案2】:

    不要手动生成 JSON;让jq 去做吧。如果您要添加到 JSON 的值需要正确引用,这一点很重要,如果您只是在 shell 中执行字符串插值,则不会发生这种情况:

    $ foo='"hi" he said'
    $ json="{ \"text\": \"$foo\" }"  
    $ echo "$json"
    { "text": ""hi" he said" }  # Wrong: should be { "text": "\"hi\" he said" }
    

    进一步,jq 可以生成日期和时间字符串;也不需要运行date(两次)。

    #!/bin/sh
    
    if [ $# -eq 7 ]; then
      printf "Wrong number of parameters: %d\n" "$#" >&2
      exit 1
    fi
    
    oper=$1 file_path=$2
    
    # Generate the new message using arguments 3-7
    new_message=$(
      jq -n --arg csv "$3" --arg step "$4" \
            --arg status "$5" --arg code "$6" \
            --arg message "$7" '{
      timestamp: now|strftime("%F:%T"),
      csv: $csv, step: $step, status: $status, code: $code, message: $message}'
    )
    
    case $oper in
      create)
        jq -n --argjson new_msg "$new_message" --arg csv "$3" '{
          date: now|strftime("%F"),
          csv: $csv,
          messages: [ $new_msg ]
        }' > "$file_path"
        ;;
    
      update)
        jq --argjson new_msg "$new_message" \
           '.messages += [ $new_msg ]' \
           "$file_path" > "$file_path.tmp" && mv "$file_path.tmp" "$file_path" ;;
    
      *) printf 'operation not recognized: %s\n' "$oper" >&2
         exit 1 ;;
    esac
    jq '.' "$file_path"
    

    【讨论】:

      【解决方案3】:

      感谢@Inian。我改变了一点,但工作....这里是解决方案。

      if [ "$#" -eq 7 ]; then
          if [ "$OPER" == "update" ]; then
              echo "update Json"
                      echo "FILE_PATH: $FILE_PATH - CSV: $CSV - STEP: $STEP - STATUS: $STATUS - CODE: $CODE - MESSAGE: $MESSAGE"
              REPORT="{\"timestamp\": \"$DATE_TIME\", \"step\": \"$STEP\", \"status\": \"$STATUS\", \"code\": \"$CODE\", \"message\": \"$MESSAGE\"}"
              echo "REPORTTTTT: "$REPORT
              echo `jq --argjson args "$REPORT" '.data.messages += [$args]' $FILE_PATH` > $FILE_PATH
          else
              echo "operation not recognized: $OPER"
          fi
      else
              echo "wrong parameters."
      fi
      

      【讨论】:

      • 这并没有为我上面的答案添加任何新内容。删除这个并将我的答案标记为已接受以将其标记为已解决
      • 为什么要使用jq生成JSON手动定义REPORT
      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 2014-06-15
      • 1970-01-01
      • 2022-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多