(Mac Terminal) sed para analisar JSON… o que estou fazendo errado?

4

No Mac Terminal, estou tentando analisar o "nome" dessa resposta JSON:

{"created_at":"2012-08-27T20:04:27Z","deleted_at":null,"id":21462840,"item_type":"video","name":"CastingBy-v12 mixed.mov","private":true,"redirect_url":null,"remote_url":"http://f.cl.ly/items/3D0P02b3e3p2I/CastingBy-v12%20mixed.mov","source":"Cloud/1.5.4 CFNetwork/520.4.3 Darwin/11.4.0 (x86_64) (MacPro5%2C1)","updated_at":"2012-08-27T20:13:38Z","view_counter":2,"href":"http://my.cl.ly/items/2840","icon":"http://my.cld.me/images/item-types/video.png","subscribed":true,"url":"http://files.housenyc.com/1I3E2F3C","content_url":"http://files.eeehousenyc.com/1I3Q0Z1E2F3C/CastingBy-v12%20mixed.mov","download_url":"http://files.eeehousenyc.com/1I3Q0F3C/download/CastingBy-v12%20mixed.mov","gauge_id":null}

Estou usando

sed 's/{.*?"name":"\(.+?\)".*//'

mas retorna toda a string.

Eu quero que ele retorne apenas

CastingBy-v12 mixed.mov

    
por Ze'ev 27.08.2012 / 22:58

5 respostas

7

Esta é a expressão que você está procurando:

sed -e 's/^.*"name":"\([^"]*\)".*$//' infile

Isso resulta em:

CastingBy-v12 mixed.mov

No seu, há vários erros:

  • Em sed , somente expressões de greeding podem ser usadas: .*? e .+? estão incorretas.
  • O + deve ter escape.
  • Use [^"]* para evitar que a expressão regular corresponda até o último aspas duplas da string.
por 27.08.2012 / 23:10
10

Analisar json com apenas sed é tão problemático quanto analisar HTML - em suma: como elementos podem incorporar outros elementos e regex não suporta recursão, é essencialmente impossível analisar corretamente com apenas regexp.

Há uma solução PCRE para analisar e validar o json aqui: link - eu não usei ou testei, então vou ter que usar a palavra do autor que funciona ... mas o PCRE faz muitas coisas que simplesmente não estão no regexps básico ou estendido suportado pelo sed.

Em qualquer caso, é melhor você usar o perl, o python ou o awk e uma das bibliotecas de análise json para essas linguagens, ou uma ferramenta de análise json especializada - várias são mencionadas aqui:

link

Qualquer um deles pode ser usado para extrair dados da entrada JSON para uso em um script de shell. Ou você pode escrever todo o seu programa dentro desse idioma.

Por exemplo, canalizar seus dados do json para python -mjson.tool resulta nisto:

$ echo "JSONDATAHERE" | python -m json.tool
{
    "content_url": "http://files.eeehousenyc.com/1I3Q0Z1E2F3C/CastingBy-v12%20mixed.mov", 
    "created_at": "2012-08-27T20:04:27Z", 
    "deleted_at": null, 
    "download_url": "http://files.eeehousenyc.com/1I3Q0F3C/download/CastingBy-v12%20mixed.mov", 
    "gauge_id": null, 
    "href": "http://my.cl.ly/items/2840", 
    "icon": "http://my.cld.me/images/item-types/video.png", 
    "id": 21462840, 
    "item_type": "video", 
    "name": "CastingBy-v12 mixed.mov", 
    "private": true, 
    "redirect_url": null, 
    "remote_url": "http://f.cl.ly/items/3D0P02b3e3p2I/CastingBy-v12%20mixed.mov", 
    "source": "Cloud/1.5.4 CFNetwork/520.4.3 Darwin/11.4.0 (x86_64) (MacPro5%2C1)", 
    "subscribed": true, 
    "updated_at": "2012-08-27T20:13:38Z", 
    "url": "http://files.housenyc.com/1I3E2F3C", 
    "view_counter": 2
}

que você pode então canalizar para o sed assim:

$ echo "JSONDATAHERE" | python -m json.tool | sed -n -e '/"name":/ s/^.*"\(.*\)".*//p'
CastingBy-v12 mixed.mov

Confiando na natureza gananciosa do regexp, o script sed extrai tudo entre o segundo e último caractere " e o último caractere " em qualquer linha contendo "name": .

    
por 28.08.2012 / 00:15
3

Isso não responde a sua pergunta diretamente. Mas se você precisar fazer essas coisas regularmente, considere o uso de uma linguagem de programação geralmente disponível como Perl, Python, Ruby.

Em Ruby, sua solução seria:

some_command_that_emits_json | ruby -e "require 'rubygems';require 'json'; output=JSON.parse(STDIN.gets); puts output['name']"

    
por 28.08.2012 / 00:25
2

Indo de este tópico , isso resolve:

echo {json...foo} | awk -F=":" -v RS="," '$1~/"name"/ {print}' | sed 's/\"//g' | sed 's/name://'

    
por 28.08.2012 / 00:14
1

Aqui está uma maneira de fazer isso com o módulo JSON de perl :

 json_producing_process | perl -MJSON -lne 'print from_json($_)->{name}'
    
por 28.08.2012 / 10:41