用jq通过shell脚本更新json

时间:2017-02-17 11:16:38

标签: json bash shell sh jq

我创建了一个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

以下是命令行&gt;&gt;

的示例
$ 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

3 个答案:

答案 0 :(得分:2)

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

--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

答案 1 :(得分:0)

谢谢@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

答案 2 :(得分:0)

不要手工生成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"