цикл через массив JSON в сценарии оболочки

Просто альтернативное решение для bash, предполагая, что путь - это абсолютный путь (начинается с /):

#!/bin/bash

pathname="$1"

IFS='/' read -r -a p <<<"${pathname#/}"

pa=""    max="${#p[@]}"    i=0
while (( i<"$max" )); do
      pa="$pa/${p[i++]}"
      if     [[ ! -e $pa ]]; then
             printf 'failed at: \t"%s"\t"%s"\n' "${pa##*/}" "${pa}"
             break
      fi
done

$ ./script "/foo/ba r/baz/hello/world"
failed at:      "hello"        "/foo/ba r/baz/hello"
6
28.12.2018, 14:54
5 ответов

Для варианта использования, представленного в Вопросе, ответ @JigglyNaga, вероятно, лучше, чем этот, но для некоторых более сложных задач вы также можете перебирать элементы списка, используяkeys:

изfile:

for k in $(jq '.children.values | keys |.[]' file); do
   ...
done

или из строки:

for k in $(jq '.children.values | keys |.[]' <<< "$MYJSONSTRING"); do
   ...
done

Так, например. вы можете использовать:

for k in $(jq '.children.values | keys |.[]' file); do
    value=$(jq -r ".children.values[$k]" file);
    name=$(jq -r '.path.name' <<< "$value");
    type=$(jq -r '.type' <<< "$value");
    size=$(jq -r '.size' <<< "$value");
    printf '%s\t%s\t%s\n' "$name" "$type" "$size";
done | column -t -s$'\t'

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

for k in $(jq '.children.values | keys |.[]' file); do
    IFS=$'\n' read -r -d '' name type size \
        <<< "$(jq -r ".children.values[$k] |.path.name,.type,.size" file)"
    printf '%s\t%s\t%s\n' "$name" "$type" "$size";
done | column -t -s$'\t'
24
27.01.2020, 20:20

Извлечение элементов

jq -c '.children.values[]|[.path.components[0],.type,.size]'
  • .children.values[]выводит каждый член массива .values.
  • |направляет предыдущий результат через следующий фильтр, как в оболочковой трубе
  • [... ,... ,... ]заставляет все термины внутри отображаться в одном массиве
  • Опция -cсоздает "компактный" формат, т.е. один объект в строке

Результат:

[".gitignore","FILE",224]
["Jenkinsfile","FILE",1396]
["README.md","FILE",237]
...

Форматирование результата

Если вы хотите вывести аккуратно выровненную -таблицу, с этой задачей лучше справятся другие инструменты, такие какcolumnилиpaste.

jq -c '.children.values[]|[.path.components[0],.type,.size]' | column -t -s'[],"'
  • -tуказывает columnугадать количество столбцов на основе ввода
  • -s...задает символ-разделитель (s)

Результат:

.gitignore   FILE       224
Jenkinsfile  FILE       1396
README.md    FILE       237

Это зависит от символов [, ], ,и ", которые не появляются в ваших именах файлов, что не является безопасным предположением.

pasteтакже может располагать несколько входов со стороны -по стороне -. Для этого мы можем вообще удалить структуры JSON и вывести необработанные строки (шляпу -подсказку к @muru):

jq -r '.children.values[]|.path.components[0],.type,.size' | paste - - -

paste - - -означает 3 столбца, все считанные из одного источника. На этот раз единственное предположение состоит в том, что имена файлов не содержат символов новой строки.

22
27.01.2020, 20:20

Решение сramda-cli:

% curl... | ramda -o tsv '.children.values' 'map flat' 'map props ["path.name", "type", "size"]'
.gitignore      FILE    224
Jenkinsfile     FILE    1396
README.md       FILE    237
pom.xml FILE    2548
src     DIRECTORY

Сначала мы переходим к списку значений, затем сопоставляем список с помощью flat, чтобы преобразовать каждую запись, которая является глубокой объектной структурой, в неглубокую, с ключами, разделенными точками.

Затем мы можем снова сопоставить список и выбрать нужные свойства на основе их путей, представленных в виде строк.

Наконец, -o tsvпреобразует результирующий список списков в формат tsv.

Чтобы отладить или лучше понять, что происходит, вы можете проверить, что делает каждый аргумент, удаляя их один за другим в конце команды и наблюдая за различиями в выводе на каждом шаге. Это просто операции (или функции ), применяемые к данным по одному слева направо.

1
27.01.2020, 20:20

jq может преобразовывать свой вывод в различные форматы :см.https://stedolan.github.io/jq/manual/#Formatstringsandescaping

Для вкладки -отдельный вывод:

$ jq -r '.children.values[] | [.path.name,.type,.size] | @tsv' file.json
.gitignore  FILE    224
Jenkinsfile FILE    1396
README.md   FILE    237
pom.xml FILE    2548
src DIRECTORY   
7
27.01.2020, 20:20

одно линейное решение на основеjtcи xargs:

bash $ jtc -x'<values>l[+0]<size>l[-1]' -y'<name>l' -y'<type>l' -y'<size>l' your.json | xargs -n3
.gitignore FILE 224
Jenkinsfile FILE 1396
README.md FILE 237
pom.xml FILE 2548
bash $ 

Примечание:в вашем файле json неправильный (ключ размера присутствует не в каждой записи ), для его исключения первый аргумент -xпостроен таким образом (обрабатывать только те записи, где размер присутствует ).

1
27.01.2020, 20:20

Теги

Похожие вопросы