Есть ли у `jq` walk` проблемы с сортировкой при ходьбе? - PullRequest
0 голосов
/ 11 июня 2019

У меня есть небольшое jq использование, где я хочу выполнить обратную сортировку по размеру дерева.Я знаю, что это возможно с du -h и sort -h и т. Д. Но я пробую это с выводом tree json и jq.

Это выглядит так:

$ tree -h -pug --du -nA -J perl5 | \
awk -v RS= '{ gsub(/,[[:space:]]*]/, "\n]", $0) }1' | \
jq '
walk(if type == "object" and has("contents")
 then (.contents|sort_by(.size)|reverse)
 else . end)'
jq: error (at <stdin>:65): Cannot index array with string "size"

Таким образом, чтобы распаковать это, используется awk, потому что вывод json tree содержит дополнительные запятые после последнего файла или каталога в массиве contents каталога.Строка 65 ввода содержит report, который выглядит следующим образом:

  {"type":"report","size":1310049,"directories":24,"files":15}

Он не содержит contents, поэтому if следует избегать его.

Вот несколько более простыхконтрольные примеры:

$ echo '
{"a":0, "c":[
  {"a":1, "s":3},
  {"a":2, "s":4}]}' | jq -c '
walk(if type == "object" and has("c") and (.c|length) > 0
 then (.c|sort_by(.s)|reverse)
 else . end)'
[{"a":2,"s":4},{"a":1,"s":3}]
$ echo '
{"a":0, "c":[
  {"a":1,"s":3, "c":[
    {"a":1,"s":5},
    {"a":2,"s":6}]},
  {"a":2,"s":4}]}' | jq -c '
walk(if type == "object" and has("c") and (.c|length) > 0
 then (.c|sort_by(.s)|reverse)
 else . end)'
jq: error (at <stdin>:1): Cannot index array with string "s"

Я не уверен, что понимаю это сообщение об ошибке и что мне не хватает в walk.

1 Ответ

2 голосов
/ 11 июня 2019

Аргумент к walk в вашем сообщении неверен.

Вы, вероятно, хотите обновить значение .contents, то есть:

walk(if type == "object" and has("contents")
  then .contents |= (sort_by(.size)|reverse)
  else . end)

(В последнем (посте-1.6) версия jq, вы можете опустить предложение else ..)

ps

Версия 1.8 tree устраняет проблему с запятой.

ЕслиВаш tree генерирует недопустимый JSON при использовании опции -J, вместо использования универсального инструмента обработки текста, такого как awk, может быть лучше использовать инструмент, такой как hjson , чтобы "дезинфицировать"псевдо-JSON, например,

tree .... | hjson -j | jq ...

pps

Чтобы понять, почему возникает ошибка, когда в качестве аргумента walk используется неверное выражение, давайте рассмотрим простой тестовый пример вOP, но со вставленным дополнительным debug, чтобы мы могли видеть, что происходит:


echo '
{"a":0, "c":[
  {"a":1,"s":3, "c":[
    {"a":1,"s":5},
    {"a":2,"s":6}]
  },
  {"a":2,"s":4}]
}' | jq -c '
  walk(if type == "object" and has("c")
       then debug | .c | sort_by(.s) | reverse
       else . end)'

(я пропустил проверку length, поскольку она просто загромождает код).

Это приводит к:

["DEBUG:",{"a":1,"s":3,"c":[{"a":1,"s":5},{"a":2,"s":6}]}]
["DEBUG:",{"a":0,"c":[[{"a":2,"s":6},{"a":1,"s":5}],{"a":2,"s":4}]}]
jq: error (at <stdin>:6): Cannot index array with string "s"

Теперь мы можем видеть проблему: вторая строка DEBUG показывает, что .c стал немного беспорядочнымle: первый элемент - это массив.Это потому, что мы заменили .c массивом.Именно по этой причине попытка использования sort_by(.s) не удалась.

Чтобы понять это более полно, необходимо проверить определение walk, что легко сделать: вы могли бы Google jq "def walk" или перейдите к источнику: builtin.jq

...