LINUX.ORG.RU

Рекурсивных обход Record в Nushell

 , nushell, , ,


0

1

Исходное сообщение о работе с JSON.

@ZogG, @Dr64h вы не в курсе как обходить рекурсивно обходить Record, чтоб получать путь и значение каждого элемента?

То что, я пока нашел не подоходит. Просто превратить весь Record в огромную однострочку табицу где данные хранятся под именами столбцов. Могу получить имена столбцов. А вот пару имя/значение пока не знаю как.

~/tmp/nu> open react_p.json | flatten | columns | where ($it | str contains "lint")
╭────┬────────────────────────────────────────────────╮
│  0 │ @typescript-eslint/eslint-plugin               │
│  1 │ @typescript-eslint/parser                      │
│  2 │ eslint                                         │
│  3 │ eslint-config-prettier                         │
│  4 │ eslint-plugin-babel                            │
│  5 │ eslint-plugin-es                               │
│  6 │ eslint-plugin-eslint-plugin                    │
│  7 │ eslint-plugin-ft-flow                          │
│  8 │ eslint-plugin-jest                             │
│  9 │ eslint-plugin-no-for-of-loops                  │
│ 10 │ eslint-plugin-no-function-declare-after-return │
│ 11 │ eslint-plugin-react                            │
│ 12 │ eslint-plugin-react-internal                   │
│ 13 │ hermes-eslint                                  │
│ 14 │ lint                                           │
│ 15 │ lint-build                                     │
╰────┴────────────────────────────────────────────────╯

Через zip я добился создание таблицы. Но в ней нет пути.

~/tmp/nu> let names = open react_p.json | flatten | columns
~/tmp/nu> let vals = open react_p.json | flatten | values
~/tmp/nu> let pairs = $names | zip $vals

~/tmp/nu> $pairs | where ($it.0 | str contains lint) |
reduce -f [[key value]; [0,0]] {|it, acc| $acc | append [[key value]; [$it.0, $it.1.0]]} |
skip 1
╭────┬────────────────────────────────────────────────┬─────────────────────────────────────────╮
│  # │                      key                       │                  value                  │
├────┼────────────────────────────────────────────────┼─────────────────────────────────────────┤
│  0 │ @typescript-eslint/eslint-plugin               │ ^6.21.0                                 │
│  1 │ @typescript-eslint/parser                      │ ^6.21.0                                 │
│  2 │ eslint                                         │ ^7.7.5                                  │
│  3 │ eslint-config-prettier                         │ ^6.9.0                                  │
│  4 │ eslint-plugin-babel                            │ ^5.3.0                                  │
│  5 │ eslint-plugin-es                               │ ^4.1.0                                  │
│  6 │ eslint-plugin-eslint-plugin                    │ ^3.5.3                                  │
│  7 │ eslint-plugin-ft-flow                          │ ^2.0.3                                  │
│  8 │ eslint-plugin-jest                             │ 28.4.0                                  │
│  9 │ eslint-plugin-no-for-of-loops                  │ ^1.0.0                                  │
│ 10 │ eslint-plugin-no-function-declare-after-return │ ^1.0.0                                  │
│ 11 │ eslint-plugin-react                            │ ^6.7.1                                  │
│ 12 │ eslint-plugin-react-internal                   │ link:./scripts/eslint-rules             │
│ 13 │ hermes-eslint                                  │ ^0.22.0                                 │
│ 14 │ lint                                           │ node ./scripts/tasks/eslint.js          │
│ 15 │ lint-build                                     │ node ./scripts/rollup/validate/index.js │
╰────┴────────────────────────────────────────────────┴─────────────────────────────────────────╯


Последнее исправление: dataman (всего исправлений: 1)

Я бы сначала попробовал jq для подобной задачи.

FishHook
()

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

rtxtxtrx ★★
()
Ответ на: комментарий от FishHook

Да это package.json из React.

https://raw.githubusercontent.com/facebook/react/refs/heads/main/package.json 
lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 2)
Ответ на: комментарий от rtxtxtrx

не используй нюшел этот. он нестандартный и его популярность меньше статистической погрешности.

Мне нравится, похож на Ruby.

lbvf50txt
() автор топика

В pwsh я бы сделал так:

$  & {                                                                                                  
        $json = (iwr https://raw.githubusercontent.com/facebook/react/refs/heads/main/package.json).content
        ($json | ConvertFrom-Json).devDependencies | select "*lint*"
    }
                                                                                                                       
@typescript-eslint/eslint-plugin               : ^6.21.0
@typescript-eslint/parser                      : ^6.21.0
eslint                                         : ^7.7.0
eslint-config-prettier                         : ^6.9.0
eslint-plugin-babel                            : ^5.3.0
eslint-plugin-es                               : ^4.1.0
eslint-plugin-eslint-plugin                    : ^3.5.3
eslint-plugin-ft-flow                          : ^2.0.3
eslint-plugin-jest                             : 28.4.0
eslint-plugin-no-for-of-loops                  : ^1.0.0
eslint-plugin-no-function-declare-after-return : ^1.0.0
eslint-plugin-react                            : ^6.7.1
eslint-plugin-react-internal                   : link:./scripts/eslint-rules
hermes-eslint                                  : ^0.22.0

dmitry237 ★★★★★
()

@FishHook, @rtxtxtrx, @dmitry237 основные коцепты Nushell которые я изучил за день.

Базовая идея следующая: утилита вместо текста отдает таблицу

~/tmp/nu> ls 
╭───┬──────────────┬──────┬────────┬────────────────╮
│ # │     name     │ type │  size  │    modified    │
├───┼──────────────┼──────┼────────┼────────────────┤
│ 0 │ edited.json  │ file │ 7.1 kB │ 6 hours ago    │
│ 1 │ react_p.json │ file │ 7.1 kB │ 6 hours ago    │
│ 2 │ table        │ file │   42 B │ an hour ago    │
│ 3 │ table.yaml   │ file │   42 B │ 26 minutes ago │
╰───┴──────────────┴──────┴────────┴────────────────╯

Внутри Nu есть два основных внутренних типа данных: таблица (почти SQL) и словарь (как в Питоне). Таблица — это основной выхлоп всех утилит, двумерный массив с именами столбцов. Также в Nu есть внутренний язык, напоминающий сильно усеченное подмножество SQL.

Формат работы такой: через набор конвейеров и упрощенного SQL обрабатывается таблица, в конце записывается в один из распространенных форматов: csv, yaml, toml.

Также есть внутренний плагин query, который позволяет при помощи селекторов (CSS-селекторов) перемещаться по HTML и JSON.

Вкратце так: Nu = Ruby + SQL + Bash. Что-то среднее, с основным типом — таблица и возможностью адресоваться в ячейки. Даже такой тип, адресация в ячейку, есть — Cell Path.

Следовательно, есть набор встроенных утилит: ls, history, ps, sys, help — которые возвращают таблицы. Также можно с легкостью обращаться за данными по протоколу HTTP и распарсивать ответы в одну строку.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 8)

Не понимаю зачем такие сложности. Ведь при помощи jq утилитки это делается элементарно:

$ jq -r '.devDependencies | to_entries[] | "\(.key) \(.value)"' package.json | column -t
@babel/cli                                      ^7.10.5
@babel/code-frame                               ^7.10.4
@babel/core                                     ^7.11.1
@babel/helper-module-imports                    ^7.10.4
@babel/parser                                   ^7.11.3
@babel/plugin-external-helpers                  ^7.10.4
@babel/plugin-proposal-class-properties         ^7.10.4
@babel/plugin-proposal-object-rest-spread       ^7.11.0
@babel/plugin-syntax-dynamic-import             ^7.8.3
@babel/plugin-syntax-import-meta                ^7.10.4
@babel/plugin-syntax-jsx                        ^7.23.3
@babel/plugin-syntax-typescript                 ^7.14.5
@babel/plugin-transform-arrow-functions         ^7.10.4
...

И дальше при помощи awk можно делать какие-угодно манипуляции.

iron ★★★★★
()
Ответ на: комментарий от iron

Не понимаю зачем такие сложности.

Дак вы задачу не ту выполнили. Надо пройти рекурсивно и полуить пары path/value.

Просто прочитать объект devDependencies из JSON тоже не сложно в Nushell. Получатся просто пары key/value, вместо полный_путь/value.

open package.json | get devDependencies

А потом еще при помощи tanspose Словарь в Таблицу перевести.

~/tmp/nu> open package.json | get devDependencies | transpose key value | first 5
╭───┬──────────────────────────────┬─────────╮
│ # │             key              │  value  │
├───┼──────────────────────────────┼─────────┤
│ 0 │ @babel/cli                   │ ^7.10.5 │
│ 1 │ @babel/code-frame            │ ^7.10.4 │
│ 2 │ @babel/core                  │ ^7.11.1 │
│ 3 │ @babel/helper-module-imports │ ^7.10.4 │
│ 4 │ @babel/parser                │ ^7.11.3 │
╰───┴──────────────────────────────┴─────────╯

Можно и поиск по строкам (Regex) устраивать.

~/tmp/nu> open package.json | get devDependencies | transpose key value | where key =~ 'parser'
╭───┬───────────────────────────────┬─────────╮
│ # │              key              │  value  │
├───┼───────────────────────────────┼─────────┤
│ 0 │ @babel/parser                 │ ^7.11.3 │
│ 1 │ @typescript-eslint/parser     │ ^6.21.0 │
│ 2 │ error-stack-parser            │ ^2.0.6  │
│ 3 │ hermes-parser                 │ ^0.22.0 │
│ 4 │ prettier-plugin-hermes-parser │ ^0.23.0 │
╰───┴───────────────────────────────┴─────────╯


lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 2)

Через zip я добился создание таблицы. Но в ней нет пути.

Не пойму как этот path должен выглядеть. Это должен быть путь по структуре?

Dr64h ★★★
()
Ответ на: комментарий от Dr64h

Не пойму как этот path должен выглядеть. Это должен быть путь по структуре?

Да, это должен быть путь по структуре. Поработав день с Nushell я пришел к выводу, что эта задача не для однострочника. Для решения такой задачи надо писать метод который будет обходить дерево объектов в JSON.

lbvf50txt
() автор топика
Ответ на: комментарий от lbvf50txt

Поработав день с Nushell я пришел к выводу, что эта задача не для однострочника.

Мне кажется это для любого языка так. Тут надо парсер с рекурсивным проходом писать. Я подобное только на плюсах делал.

Dr64h ★★★
()
Ответ на: комментарий от Dr64h

Мне кажется это для любого языка так. Тут надо парсер с рекурсивным проходом писать. Я подобное только на плюсах делал.

Алгоритм называется Backtracking.

lbvf50txt
() автор топика

Какое извращенское извращение. В более другом shell, такое (если я правильно понял задачу) можно изобразить так

(def url "https://raw.githubusercontent.com/facebook/react/refs/heads/main/package.json")
(def db (-> url http/get :body json/parse-string (get "devDependencies")))
(->> db keys (filter #(re-matches #".*lint.*" %))  (select-keys db))
{"eslint" "^7.7.0",
 "eslint-plugin-jest" "28.4.0",
 "eslint-plugin-no-for-of-loops" "^1.0.0",
 "eslint-plugin-eslint-plugin" "^3.5.3",
 "@typescript-eslint/parser" "^6.21.0",
 "eslint-config-prettier" "^6.9.0",
 "eslint-plugin-no-function-declare-after-return" "^1.0.0",
 "eslint-plugin-react" "^6.7.1",
 "@typescript-eslint/eslint-plugin" "^6.21.0",
 "eslint-plugin-ft-flow" "^2.0.3",
 "eslint-plugin-react-internal" "link:./scripts/eslint-rules",
 "eslint-plugin-es" "^4.1.0",
 "eslint-plugin-babel" "^5.3.0",
 "hermes-eslint" "^0.22.0"}
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

То что ты сделал, можно сделать так:

open react_p.json | get devDependencies | transpose key val | where ($it.key | str contains lint)
╭────┬────────────────────────────────────────────────┬─────────────────────────────╮
│  # │                      key                       │             val             │
├────┼────────────────────────────────────────────────┼─────────────────────────────┤
│  0 │ @typescript-eslint/eslint-plugin               │ ^6.21.0                     │
│  1 │ @typescript-eslint/parser                      │ ^6.21.0                     │
│  2 │ eslint                                         │ ^7.7.0                      │
│  3 │ eslint-config-prettier                         │ ^6.9.0                      │
│  4 │ eslint-plugin-babel                            │ ^5.3.0                      │
│  5 │ eslint-plugin-es                               │ ^4.1.0                      │
│  6 │ eslint-plugin-eslint-plugin                    │ ^3.5.3                      │
│  7 │ eslint-plugin-ft-flow                          │ ^2.0.3                      │
│  8 │ eslint-plugin-jest                             │ 28.4.0                      │
│  9 │ eslint-plugin-no-for-of-loops                  │ ^1.0.0                      │
│ 10 │ eslint-plugin-no-function-declare-after-return │ ^1.0.0                      │
│ 11 │ eslint-plugin-react                            │ ^6.7.1                      │
│ 12 │ eslint-plugin-react-internal                   │ link:./scripts/eslint-rules │
│ 13 │ hermes-eslint                                  │ ^0.22.0                     │
╰────┴────────────────────────────────────────────────┴─────────────────────────────╯

Но как я понял, нужно получить последовательность ключей по структуре, что-то типа:
key [key, key...] : value

Dr64h ★★★
()
Ответ на: комментарий от FishHook

как вы ее описали, так и выполнили. Я тоже не понял, что вы хотите.

Есть такое, описано не очень точно. Уже разобрались как и что делать.

lbvf50txt
() автор топика
Последнее исправление: lbvf50txt (всего исправлений: 1)
Ответ на: комментарий от lbvf50txt
import json

def items(parent_path: str, struct: dict):
    for k, v in struct.items():
        path = f"{parent_path}/{k}"
        if isinstance(v, dict):
            yield from items(path,  v)
        elif isinstance(v, str):
            yield path, v

with open("package.json") as f:
    data = json.load(f)
    for p, v in items("", data):
       print(p, "-->", v)

FishHook
()
Ответ на: комментарий от Dr64h

После того как превратили Record в Table через transpose уже можно по столбцам поиск осуществлять через регулярные выражение, короче получается.

# Nushell

open package.json | get devDependencies | transpose key value | where key =~ 'parser'

open react_p.json | get devDependencies | transpose key val | where ($it.key | str contains lint)
lbvf50txt
() автор топика
Ответ на: комментарий от Dr64h

последовательность ключей по структуре,

В смысле сгруппировать все библиотеки с одним и тем же номером версии?

P.S. версии-перверсии, всё извращённей и извращённей.

ugoday ★★★★★
()

Возьми уже просто ноду и не мучай жопу. Нахер не упали все эти jq, nu и прочее.

no-such-file ★★★★★
()

А что за штука этот нус хелл?

ya-betmen ★★★★★
()
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.