Например, специальные выражения типа \ w в скобочных выражениях [] - PullRequest
2 голосов
/ 14 марта 2019

Я пытаюсь использовать расширенный grep для извлечения данных из JSON.Регулярное выражение, которое я использую, работает на моем экземпляре regexr , но по какой-то причине оно не работает в bash.

Я пробовал много вещей, в частности голая двойная черта и различные незначительные правки в регулярное выражение для экранирования.

#!/bin/bash
networks='{ "networks": [ { "admin_state_up": true, "availability_zone_hints": [], "availability_zones": [], "created_at": "2019-03-12T23:45:13Z", "description": "", "id": "7188504a-72cb-4590-a9b0-414732017837", "ipv4_address_scope": null, "ipv6_address_scope": null, "is_default": false, "mtu": 1450, "name": "BLUE", "port_security_enabled": true, "project_id": "187d635aec4c43fe8e8918afb3a5c82e", "provider:network_type": "vxlan", "provider:physical_network": null, "provider:segmentation_id": 86, "revision_number": 2, "router:external": false, "shared": false, "status": "ACTIVE", "subnets": [], "tags": [], "tenant_id": "187d635aec4c43fe8e8918afb3a5c82e", "updated_at": "2019-03-12T23:45:13Z" }, { "admin_state_up": true, "availability_zone_hints": [], "availability_zones": [], "created_at": "2019-03-12T23:45:13Z", "description": "", "id": "ed82083f-0a7c-4322-a4fb-de8db23e2bae", "ipv4_address_scope": null, "ipv6_address_scope": null, "is_default": false, "mtu": 1450, "name": "RED", "port_security_enabled": true, "project_id": "187d635aec4c43fe8e8918afb3a5c82e", "provider:network_type": "vxlan", "provider:physical_network": null, "provider:segmentation_id": 108, "revision_number": 2, "router:external": false, "shared": false, "status": "ACTIVE", "subnets": [], "tags": [], "tenant_id": "187d635aec4c43fe8e8918afb3a5c82e", "updated_at": "2019-03-12T23:45:13Z" }, { "admin_state_up": true, "availability_zone_hints": [], "availability_zones": [], "created_at": "2019-03-12T23:45:13Z", "description": "", "id": "1eb6647e-869e-4e83-9468-43e2c320bccc", "ipv4_address_scope": null, "ipv6_address_scope": null, "is_default": false, "mtu": 1450, "name": "public", "port_security_enabled": true, "project_id": "187d635aec4c43fe8e8918afb3a5c82e", "provider:network_type": "vxlan", "provider:physical_network": null, "provider:segmentation_id": 32, "revision_number": 2, "router:external": false, "shared": false, "status": "ACTIVE", "subnets": [], "tags": [], "tenant_id": "187d635aec4c43fe8e8918afb3a5c82e", "updated_at": "2019-03-12T23:45:13Z" } ] }'
result=`echo $networks | grep -oE '"(id|name)": "([\w+-]+)"'`
echo $result

Вышеупомянутый код не работает, но еслиЯ переключаюсь на следующее регулярное выражение, это работает.Мне просто нужно добавить извлечение для поля id, чтобы иметь возможность извлекать идентификаторы и имена, используя обратную ссылку \ 2 (группа 2)

grep -oE '"(id|name)": "(\w+)"'

Можете ли вы помочь мне понять, почему скрипт не работает?

полный формат JSON

{
  "networks": [{
    "admin_state_up": true,
    "availability_zone_hints": [],
    "availability_zones": [],
    "created_at": "2019-03-12T23:45:13Z",
    "description": "",
    "id": "7188504a-72cb-4590-a9b0-414732017837",
    "ipv4_address_scope": null,
    "ipv6_address_scope": null,
    "is_default": false,
    "mtu": 1450,
    "name": "BLUE",
    "port_security_enabled": true,
    "project_id": "187d635aec4c43fe8e8918afb3a5c82e",
    "provider:network_type": "vxlan",
    "provider:physical_network": null,
    "provider:segmentation_id": 86,
    "revision_number": 2,
    "router:external": false,
    "shared": false,
    "status": "ACTIVE",
    "subnets": [],
    "tags": [],
    "tenant_id": "187d635aec4c43fe8e8918afb3a5c82e",
    "updated_at": "2019-03-12T23:45:13Z"
  }, {
    "admin_state_up": true,
    "availability_zone_hints": [],
    "availability_zones": [],
    "created_at": "2019-03-12T23:45:13Z",
    "description": "",
    "id": "ed82083f-0a7c-4322-a4fb-de8db23e2bae",
    "ipv4_address_scope": null,
    "ipv6_address_scope": null,
    "is_default": false,
    "mtu": 1450,
    "name": "RED",
    "port_security_enabled": true,
    "project_id": "187d635aec4c43fe8e8918afb3a5c82e",
    "provider:network_type": "vxlan",
    "provider:physical_network": null,
    "provider:segmentation_id": 108,
    "revision_number": 2,
    "router:external": false,
    "shared": false,
    "status": "ACTIVE",
    "subnets": [],
    "tags": [],
    "tenant_id": "187d635aec4c43fe8e8918afb3a5c82e",
    "updated_at": "2019-03-12T23:45:13Z"
  }, {
    "admin_state_up": true,
    "availability_zone_hints": [],
    "availability_zones": [],
    "created_at": "2019-03-12T23:45:13Z",
    "description": "",
    "id": "1eb6647e-869e-4e83-9468-43e2c320bccc",
    "ipv4_address_scope": null,
    "ipv6_address_scope": null,
    "is_default": false,
    "mtu": 1450,
    "name": "public",
    "port_security_enabled": true,
    "project_id": "187d635aec4c43fe8e8918afb3a5c82e",
    "provider:network_type": "vxlan",
    "provider:physical_network": null,
    "provider:segmentation_id": 32,
    "revision_number": 2,
    "router:external": false,
    "shared": false,
    "status": "ACTIVE",
    "subnets": [],
    "tags": [],
    "tenant_id": "187d635aec4c43fe8e8918afb3a5c82e",
    "updated_at": "2019-03-12T23:45:13Z"
  }]
}

Ответы [ 3 ]

2 голосов
/ 14 марта 2019

Согласно man grep :

Символ обратной косой черты и специальные выражения

Символ \ w является синонимом для [[: alnum:]], а \ W является синонимом для [^ [: alnum:]]. ... Выражение в скобках - это список символов, заключенных в [и]. ... Чтобы включить литерал], поместите его первым в списке. Точно так же, чтобы включить литерал ^ поместите его где угодно, но не первым. Наконец, чтобы включить литерал - поместите его последним.

По сути, \w это буквально , заменяемый этими символами при оценке, давая вам "([[[:alnum:]]+-]+)", что в стандартном стандарте США дает вам "([[a-zA-Z0-9]+-]+)".

Так как выражение в скобках усекается первым ], который он видит (если это не первый элемент выражения в скобках), группа имеет значение только [[[:alnum:]]+, или "1 или более из цифры, буквы и [. За этим выражением следует -]+, что означает "ровно один дефис и один или несколько ]". Это, очевидно, довольно ужасно.

Если вы попробуете

echo $networks | grep -oE '"(id|name)": "([[:alnum:]+-]+)"'

То есть, \w без выражения внешней скобки, соответствующая часть означает «группу (окруженную "), состоящую из одной или нескольких цифр, букв, дефисов и знаков плюс», которая выдает:

"id": "7188504a-72cb-4590-a9b0-414732017837"
"name": "BLUE"
"id": "ed82083f-0a7c-4322-a4fb-de8db23e2bae"
"name": "RED"
"id": "1eb6647e-869e-4e83-9468-43e2c320bccc"
"name": "public"
1 голос
/ 14 марта 2019

Использование PERL (-P) вместо расширенного (-E) регулярного выражения, похоже, что \w интерпретируется должным образом, без экранирования: обратите внимание на -oP

result=$( echo $networks | grep -oP '"(id|name)": "([\w+-]+)"' ) ; 
echo $result
"id": "7188504a-72cb-4590-a9b0-414732017837" "name": "BLUE" "id": "ed82083f-0a7c-4322-a4fb-de8db23e2bae" "name": "RED" "id": "1eb6647e-869e-4e83-9468-43e2c320bccc" "name": "public"
0 голосов
/ 14 марта 2019

В качестве обходного пути (это не решает проблему «экранирования» \w)

result=$( echo $networks | grep -oE '"(id|name)": "([a-zA-Z_+-]+)"' ) ; 
echo $result

Печатает меня:

"name": "BLUE" "name": "RED" "name": "public"

Примечание: предпочитайте использовать синтаксис $( ) для выполнения подоболочек, а не обратного удара.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...