Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用Unix工具解析JSON_Json_Bash_Parsing_Node - Fatal编程技术网

使用Unix工具解析JSON

使用Unix工具解析JSON,json,bash,parsing,node,Json,Bash,Parsing,Node,我试图解析从curl请求返回的JSON,如下所示: curl 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}' 如何打印特定字段(由-v k=text表示)?有许多工具专门设计用于从命令行操作JSON,与使用Awk相比,这些工具更容易、更可靠,例如:

我试图解析从curl请求返回的JSON,如下所示:

curl 'http://twitter.com/users/username.json' |
    sed -e 's/[{}]/''/g' | 
    awk -v k="text" '{n=split($0,a,","); for (i=1; i<=n; i++) print a[i]}'

如何打印特定字段(由
-v k=text
表示)?

有许多工具专门设计用于从命令行操作JSON,与使用Awk相比,这些工具更容易、更可靠,例如:

您还可以使用可能已经安装在系统上的工具(如使用的Python)来实现这一点,从而避免任何额外的依赖项,同时仍然可以使用适当的JSON解析器。以下假设您希望使用UTF-8,原始JSON应该使用UTF-8编码,并且大多数现代终端也使用UTF-8:

Python 3:

curl -s 'https://api.github.com/users/lambda' | \
    python3 -c "import sys, json; print(json.load(sys.stdin)['name'])"
Python 2:

export PYTHONIOENCODING=utf8
curl -s 'https://api.github.com/users/lambda' | \
    python2 -c "import sys, json; print json.load(sys.stdin)['name']"
常见问题 为什么不是纯shell解决方案? 该标准是一种非常有限的语言,不包含表示序列(列表或数组)或关联数组(在某些其他语言中也称为哈希表、映射、dict或对象)的工具。这使得在可移植的shell脚本中表示解析JSON的结果有些棘手。有,但如果键或值包含某些特殊字符,其中许多可能会中断

Bash 4及更高版本、zsh和ksh都支持阵列和关联阵列,但这些shell并不普遍可用(macOS在Bash 3停止更新Bash,原因是从GPLv2更改为GPLv3,而许多Linux系统没有现成安装zsh)。您可以编写一个可以在bash4或zsh中工作的脚本,目前大多数macOS、Linux和BSD系统上都可以使用其中的一个,但是要编写一个适用于这种多语言脚本的shebang行是很困难的

最后,在shell中编写一个完整的JSON解析器将是一个非常重要的依赖项,您可以使用现有的依赖项,如jq或Python。要实现一个好的实现,它不会是一行代码,甚至不会是一个五行代码的小片段

为什么不使用awk、sed或grep? 可以使用这些工具以已知的形状和格式(例如每行一个键)快速提取JSON。在其他答案中,有几个建议的例子

然而,这些工具是为基于行或基于记录的格式设计的;它们不是为递归解析可能包含转义字符的匹配分隔符而设计的

因此,这些使用awk/sed/grep的快速而肮脏的解决方案很可能是脆弱的,如果输入格式的某些方面发生更改,例如折叠空白,或向JSON对象添加额外级别的嵌套,或字符串中的转义引号,这些解决方案就会崩溃。一个足够健壮的解决方案能够在不中断的情况下处理所有JSON输入,它也将相当大和复杂,因此与添加另一个对
jq
或Python的依赖关系没有太大区别

以前,由于shell脚本中的输入解析不好,我不得不处理大量被删除的客户数据,因此我从不建议使用这种方式可能很脆弱的快速而肮脏的方法。如果您正在做一些一次性处理,请参阅其他答案以获取建议,但我仍然强烈建议只使用现有的经过测试的JSON解析器

历史笔记 这个答案最初是推荐的,应该仍然有效,但使用起来比
jq
要麻烦一些,并且取决于安装的独立JavaScript解释器,而独立JavaScript解释器不如Python解释器常见,因此上述答案可能更可取:

curl -s 'https://api.github.com/users/lambda' | jsawk -a 'return this.name'
这个答案最初也使用了问题中的Twitter API,但该API不再工作,因此很难复制示例进行测试,而新的Twitter API需要API密钥,因此我转而使用GitHub API,该API无需API密钥即可轻松使用。原问题的第一个答案是:

curl 'http://twitter.com/users/username.json' | jq -r '.text'
json2tsv id text < tweets.json | tsvawk '{print "tweet " $id " is: " $text}'
 xidel -e 'json("http://twitter.com/users/username.json")("name")'
Invoke-WebRequest 'https://api.github.com/users/lambda' | select -ExpandProperty Content | ConvertFrom-Json
使用而不是使用awk

大概是这样的:

powershell 'curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json'
{
"Name":  "Tester",
"SomeList":  [
                 "one",
                 "two",
                 "three"
             ]
curl-shttp://twitter.com/users/username.json | \
python-c“导入json,sys;obj=json.load(sys.stdin);打印(obj['name'])

你问过如何射中自己的脚,我来这里提供弹药:

curl -s 'http://twitter.com/users/username.json' | sed -e 's/[{}]/''/g' | awk -v RS=',"' -F: '/^text/ {print $2}'
您可以使用
tr-d'{}'
而不是
sed
。但将它们完全排除在外似乎也能达到预期效果

如果要去掉外部引号,请通过
sed的//\(^“\\\\”$\)//g'


我认为其他人已经敲响了足够的警钟。我会拿着手机准备叫救护车。准备好后开火。

这里有一种方法可以使用awk

curl -sL 'http://twitter.com/users/username.json' | awk -F"," -v k="text" '{
    gsub(/{|}/,"")
    for(i=1;i<=NF;i++){
        if ( $i ~ k ){
            print $i
        }
    }
}'
curl-sL'http://twitter.com/users/username.json“|awk-F”,“-v k=“text””{
gsub(/{}/,“”)

对于使用Ruby和

$
或者更简洁地说:

$ < file.json ruby -r rubygems -r json -e "puts JSON.pretty_generate(JSON[STDIN.read]);"
$
由Martinar和Boecko领导:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool
这将为您提供极为友好的grep输出。非常方便:

$ curl -s 'http://twitter.com/users/username.json' | python -mjson.tool | grep my_key

为了快速提取特定键的值,我个人喜欢使用“grep-o”,它只返回正则表达式的匹配项

grep -Po '"text":.*?[^\\]",' tweets.json
array (
  'BD' => 'BGD',
  'BE' => 'BEL',
  'BF' => 'BFA',
  'BG' => 'BGR',
  'BA' => 'BIH',
  'BB' => 'BRB',
  'WF' => 'WLF',
  'BL' => 'BLM',
  ...
这个正则表达式比你想象的更健壮;例如,它可以很好地处理嵌入逗号和转义引号的字符串。我认为,再多做一点工作,你就可以制作出一个真正保证提取值的正则表达式,如果它是原子的(如果它有嵌套,那么正则表达式当然不能这样做)

为了进一步清理(尽管保留字符串的原始转义),您可以使用如下内容:
|perl-pe's/“text”://;s/^/;s/“,$/”
(我这样做是为了。)

对于所有坚持您应该使用真正的JSON解析器的人来说——是的,这对于corr来说是必不可少的
#!/bin/bash
. ticktick.sh

``  
  people = { 
    "Writers": [
      "Rod Serling",
      "Charles Beaumont",
      "Richard Matheson"
    ],  
    "Cast": {
      "Rod Serling": { "Episodes": 156 },
      "Martin Landau": { "Episodes": 2 },
      "William Shatner": { "Episodes": 2 } 
    }   
  }   
``  

function printDirectors() {
  echo "  The ``people.Directors.length()`` Directors are:"

  for director in ``people.Directors.items()``; do
    printf "    - %s\n" ${!director}
  done
}   

`` people.Directors = [ "John Brahm", "Douglas Heyes" ] ``
printDirectors

newDirector="Lamont Johnson"
`` people.Directors.push($newDirector) ``
printDirectors

echo "Shifted: "``people.Directors.shift()``
printDirectors

echo "Popped: "``people.Directors.pop()``
printDirectors
curl 'http://twitter.com/users/username.json' | jshon -e text
curl $url | grep $var | awk '{print $2}' | sed s/\"//g 
curl $url | sed '/text/!d' | sed s/\"text\"://g | sed s/\"//g | sed s/\ //g
$ export JSON='{"hostname":"test","domainname":"example.com"}'
$ echo $JSON|php -r 'echo json_decode(file_get_contents("php://stdin"))->hostname;'
$ echo $JSON|php -r 'echo json_decode(fgets(STDIN))->hostname;'
$ curl 'https://twitter.com/users/username.json' | ./jq -r '.name'
 xidel -e 'json("http://twitter.com/users/username.json")("name")'
 xidel -e 'json("http://twitter.com/users/username.json").name'
$ node -pe 'JSON.parse(process.argv[1]).foo' "$(cat foobar.json)"
bar
access_token=$(curl <some horrible crap> | jsonlookup access token id)
#!/usr/bin/python                                                               

import sys
import json

try: rep = json.loads(sys.stdin.read())
except:
    sys.stderr.write(sys.argv[0] + ": unable to parse JSON from stdin\n")
    sys.exit(2)
for key in sys.argv[1:]:
    if key not in rep:
        sys.exit(1)
    rep = rep[key]
print rep
function getJsonVal () { 
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))"; 
}
$ curl 'http://twitter.com/users/username.json' | getJsonVal "['text']"
My status
$ 
function getJsonVal() {
   if [ \( $# -ne 1 \) -o \( -t 0 \) ]; then
       cat <<EOF
Usage: getJsonVal 'key' < /tmp/
 -- or -- 
 cat /tmp/input | getJsonVal 'key'
EOF
       return;
   fi;
   python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1))";
}
$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']['a'][1]"
2
function getJsonVal () { 
    python -c "import json,sys;sys.stdout.write(json.dumps(json.load(sys.stdin)$1, sort_keys=True, indent=4))"; 
}

$ echo '{"foo": {"bar": "baz", "a": [1,2,3]}}' |  getJsonVal "['foo']"
{
    "a": [
        1, 
        2, 
        3
    ], 
    "bar": "baz"
}
{ "store": {
    "book": [ 
      { "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      { "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      },
      { "category": "fiction",
        "author": "Herman Melville",
        "title": "Moby Dick",
        "isbn": "0-553-21311-3",
        "price": 8.99
      },
      { "category": "fiction",
        "author": "J. R. R. Tolkien",
        "title": "The Lord of the Rings",
        "isbn": "0-395-19395-8",
        "price": 22.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  }
}
$ cat file.json | python -c "import sys, json, jsonpath; print '\n'.join(jsonpath.jsonpath(json.load(sys.stdin), 'store.book[?(@.price < 10)].title'))"
Sayings of the Century
Moby Dick
curl 'http://twitter.com/users/username.json' | py 'json.load(sys.stdin)["name"]'
function parse_json()
{
    echo $1 | \
    sed -e 's/[{}]/''/g' | \
    sed -e 's/", "/'\",\"'/g' | \
    sed -e 's/" ,"/'\",\"'/g' | \
    sed -e 's/" , "/'\",\"'/g' | \
    sed -e 's/","/'\"---SEPERATOR---\"'/g' | \
    awk -F=':' -v RS='---SEPERATOR---' "\$1~/\"$2\"/ {print}" | \
    sed -e "s/\"$2\"://" | \
    tr -d "\n\t" | \
    sed -e 's/\\"/"/g' | \
    sed -e 's/\\\\/\\/g' | \
    sed -e 's/^[ \t]*//g' | \
    sed -e 's/^"//'  -e 's/"$//'
}


parse_json '{"username":"john, doe","email":"john@doe.com"}' username
parse_json '{"username":"john doe","email":"john@doe.com"}' email

--- outputs ---

john, doe
johh@doe.com
echo "{\"field\": \"value\"}" | python -c 'import sys, json
print(json.load(sys.stdin)["field"])'
php -r 'var_export(json_decode(`curl http://twitter.com/users/username.json`, 1));'
curl http://country.io/iso3.json
php -r 'var_export(json_decode(`curl http://country.io/iso3.json`, 1));'
array (
  'BD' => 'BGD',
  'BE' => 'BEL',
  'BF' => 'BFA',
  'BG' => 'BGR',
  'BA' => 'BIH',
  'BB' => 'BRB',
  'WF' => 'WLF',
  'BL' => 'BLM',
  ...
# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="FooBar":")(.*?)(?=",)'
he\"llo
# echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="TotalPages":)(.*?)(?=,)'
33
#  echo '{"TotalPages":33,"FooBar":"he\"llo","anotherValue":100}' | grep -Po '(?<="anotherValue":)(.*?)(?=})'
100
curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json 
curl -s 'https://api.github.com/users/lambda' | ConvertFrom-Json | select -ExpandProperty id
powershell 'curl -s "https://api.github.com/users/lambda" | ConvertFrom-Json'
Invoke-WebRequest 'https://api.github.com/users/lambda' | select -ExpandProperty Content | ConvertFrom-Json
(New-Object PsObject -Property @{ Name = "Tester"; SomeList = @('one','two','three')}) | ConvertTo-Json
{
"Name":  "Tester",
"SomeList":  [
                 "one",
                 "two",
                 "three"
             ]
curl http://www.arcgis.com/sharing/rest/info?f=json | tee arcgis.json
# {"owningSystemUrl":"https://www.arcgis.com","authInfo":{"tokenServicesUrl":"https://www.arcgis.com/sharing/rest/generateToken","isTokenBasedSecurity":true}}

cat arcgis.json | jq
# {
#     "owningSystemUrl": "https://www.arcgis.com",
#     "authInfo": {
#         "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#         "isTokenBasedSecurity": true
#     }
# }

cat arcgis.json | jq '[ "authInfo" ]'
# {
#     "tokenServicesUrl": "https://www.arcgis.com/sharing/rest/generateToken",
#     "isTokenBasedSecurity": true
# }

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]'
# "https://www.arcgis.com/sharing/rest/generateToken"

cat arcgis.json | jq '[ "authInfo" ][ "tokenServicesUrl" ]' | unquote
# https://www.arcgis.com/sharing/rest/generateToken
function json_extract() {
  local key=$1
  local json=$2

  local string_regex='"([^"\]|\\.)*"'
  local number_regex='-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?'
  local value_regex="${string_regex}|${number_regex}|true|false|null"
  local pair_regex="\"${key}\"[[:space:]]*:[[:space:]]*(${value_regex})"

  if [[ ${json} =~ ${pair_regex} ]]; then
    echo $(sed 's/^"\|"$//g' <<< "${BASH_REMATCH[1]}")
  else
    return 1
  fi
}
$ json_extract text "$(curl 'http://twitter.com/users/username.json')"
My status

$ json_extract friends_count "$(curl 'http://twitter.com/users/username.json')"
245
#!/usr/bin/env bash
my_val="$(json=$(<package.json) node -pe "JSON.parse(process.env.json)['version']")"
$ echo '{"key": "value"}' | fx "x => x.key"
value
$ echo '[1,2,3]' | fx "this.map(x => x * 2)"
[2, 4, 6]
$ echo '{"items": {"one": 1}}' | fx .items.one
1
$ echo '{"items": ["one", "two"]}' | fx "this.items" "this[1]"
two
$ echo '{"count": 0}' | fx "{...this, count: 1}"
{"count": 1}
awk 'BEGIN { FS="\""; RS="," }; { if ($2 == "login") {print $4} }' test.json
eval $( curl -s 'https://api.github.com/users/lambda' | 
awk ' BEGIN { FS="\""; RS="," };
{
    if ($2 == "login") { print "Login=\""$4"\"" }
    if ($2 == "name") { print "Name=\""$4"\"" }
    if ($2 == "updated_at") { print "Updated=\""$4"\"" }
}' )
echo "$Login, $Name, $Updated"