Выходная строка, разделенная точкой с запятой - PullRequest
0 голосов
/ 05 ноября 2018

Допустим, у нас есть этот файл:

{
  "persons": [
    {
      "friends": 4,
      "phoneNumber": 123456,
      "personID": 11111
    },
    {
      "friends": 2057,
      "phoneNumber": 432100,
      "personID": 22222
    },
    {
      "friends": 50,
      "phoneNumber": 147258,
      "personID": 55555
    }
  ]
}

Теперь я хочу извлечь номера телефонов лиц 11111, 22222, 33333, 44444 и 55555 в виде строки, разделенной точкой с запятой:

123456;432100;;;147258

во время работы

cat persons.txt | jq ".persons[] | select(.personID==<ID>) | .phoneNumber"

один раз для каждого <ID> и склеивание результатов вместе с ; после этого работает, это ужасно медленно, потому что необходимо перезагрузить файл для каждого из идентификаторов (и других полей, которые я хочу извлечь).

Объединить его в одном запросе:

 cat persons.txt | jq "(.persons[] | select(.personID==11111) | .phoneNumber), (.persons[] | select(.personID==22222) | .phoneNumber), (.persons[] | select(.personID==33333) | .phoneNumber), (.persons[] | select(.personID==44444) | .phoneNumber), (.persons[] | select(.personID==55555) | .phoneNumber)"

Это тоже работает, но дает

123456
432100
147258

поэтому я не знаю, какие поля пропущены и сколько ; мне нужно вставить.

Ответы [ 3 ]

0 голосов
/ 06 ноября 2018

К сожалению, я не смог проверить, работает ли ответ пика , так как у меня только jq 1.5. Вот что я придумал вчера вечером:

  • Для каждой точки с запятой добавьте следующий запрос

    (\";\" as \$a | \$a)
    
  • Результирующая команда (аннотация):

     cat persons.txt | jq "(<1's phone number>), (\";\" as \$a | \$a), 
     (<2's phone number>), (\";\" as \$a | \$a), ..."
    
  • Результирующая команда (бетон):

    cat persons.txt | jq "(.persons[] | select(.personID==11111) | .phoneNumber), (\";\" as \$a | \$a), 
    (.persons[] | select(.personID==22222) | .phoneNumber), (\";\" as \$a | \$a), 
    (.persons[] | select(.personID==33333) | .phoneNumber), (\";\" as \$a | \$a), 
    (.persons[] | select(.personID==44444) | .phoneNumber), (\";\" as \$a | \$a), 
    (.persons[] | select(.personID==55555) | .phoneNumber)"
    
  • Результат:

    123456
    ";"
    432100
    ";"
    ";"
    ";"
    147258
    
  • Удалить символы новой строки и ":

    <commandAsAbove> | tr --delete "\n\""
    
  • Результат:

    123456;432100;;;147258
    

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

0 голосов
/ 06 ноября 2018

Без решения jq:

for i in $(seq 11111 11111 55555)
do
  string=$(grep -B1 "$i" persons.txt | head -1 | sed 's/.* \(.*\),/\1/g')
  echo "$string;" >> output
done
cat output | tr -d '\n' | rev | cut -d';' -f2- | rev > tmp && mv tmp output

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

cat output
123456;432100;;;147258
0 голосов
/ 05 ноября 2018

С вашим примером ввода в input.json и использованием jq 1.6 (или jq с INDEX / 2) следующий вызов jq дает желаемый результат:

jq -r --argjson ids '[11111, 22222, 33333, 44444, 55555]' -f tossv.jq input.json 

при условии, что tossv.jq содержит программу:

INDEX(.persons[]; .personID) as $dict
| $ids
| map( $dict[tostring] | .phoneNumber)
| join(";")

Примечания к программе

  1. INDEX / 2 создает объект JSON, который служит словарем. Поскольку ключи JSON должны быть строками, tostring должен использоваться в строке 3 выше.

  2. При использовании join(";") значения null фактически становятся пустыми строками.

  3. Если ваш jq не имеет INDEX / 2, то сейчас самое время обновить. В противном случае вы можете перехватить его определение, прибегнув к помощи: jq "def INDEX" builtin.jq

...