jq: khóa in và giá trị cho mỗi mục nhập trong một đối tượng


79

Làm cách nào để lấy jq lấy json như sau:

{
  "host1": { "ip": "10.1.2.3" },
  "host2": { "ip": "10.1.2.2" },
  "host3": { "ip": "10.1.18.1" }
}

và tạo đầu ra này:

host1, 10.1.2.3
host2, 10.1.2.2
host3, 10.1.18.1

Tôi không quan tâm đến định dạng, tôi chỉ không thể tìm ra cách truy cập vào tên và giá trị khóa.

Câu trả lời:


123

Để nhận các khóa cấp cao nhất dưới dạng luồng, bạn có thể sử dụng chức năng tích hợp sẵn keys[] . Vì vậy, một giải pháp cho vấn đề cụ thể của bạn sẽ là:

jq -r 'keys[] as $k | "\($k), \(.[$k] | .ip)"' 

keystạo ra các tên khóa theo thứ tự đã sắp xếp; nếu bạn muốn chúng theo thứ tự ban đầu, hãy sử dụng keys_unsorted.

Một giải pháp thay thế khác, tạo ra các khóa theo thứ tự ban đầu, là:

jq -r 'to_entries[] | "\(.key), \(.value | .ip)"'

Đầu ra CSV và TSV

Các bộ lọc @csv và @tsv cũng có thể đáng xem xét ở đây, ví dụ:

jq -r 'to_entries[] | [.key, .value.ip] | @tsv'

sản xuất:

host1   10.1.2.3
host2   10.1.2.2
host3   10.1.18.1

Các đối tượng được nhúng

Nếu các khóa quan tâm được nhúng như trong ví dụ sau, bộ lọc jq sẽ phải được sửa đổi dọc theo các dòng được hiển thị.

Đầu vào:

{
  "myhosts": {
    "host1": { "ip": "10.1.2.3" },
    "host2": { "ip": "10.1.2.2" },
    "host3": { "ip": "10.1.18.1" }
  }
}

Sửa đổi:

jq -r '.myhosts | keys[] as $k | "\($k), \(.[$k] | .ip)"'

Giả sử khóa ".ip" có khoảng trắng trong đó, chẳng hạn như "địa chỉ ip", làm cách nào để thoát khỏi các dấu ngoặc kép xung quanh khóa, cho rằng bạn sẽ ở cấp thứ ba của chuỗi được trích dẫn, nếu điều đó hợp lý?
Saichovsky

1
Vâng, nó có lý, và đó là một câu hỏi hay, nhưng hãy tha thứ cho tôi vì đã nói, bạn có thể dễ dàng tự trả lời nó, vì câu trả lời chỉ đơn giản là bỏ qua sự phức tạp tiềm ẩn. Đó là, cách tiếp cận thông thường sẽ là trích dẫn chuỗi-có-dấu cách, et voilà.
cao điểm

Tôi đã thử mà không thành công. Đã cố gắng thoát khỏi các dấu ngoặc kép nhưng nó không hoạt động, do đó câu hỏi.
Saichovsky

1
@Saichovsky - Tôi đã kiểm tra nó hoạt động ở jq 1.4, 1.5 và 1.6. Nếu bạn đang sử dụng jq 1.3, bạn phải viết .["id address"], như bạn vẫn phải làm trong trường hợp bình thường.
cao điểm

47

Đã đến giải pháp rất thanh lịch

jq 'with_entries(.value |= .ip)'

Ouputs nào

{
  "host1": "10.1.2.3",
  "host2": "10.1.2.2",
  "host3": "10.1.18.1"
}

Đây là đoạn mã jqplay để chơi với: https://jqplay.org/s/Jb_fnBveMQ

Hàm with_entrieschuyển đổi từng đối tượng trong danh sách đối tượng thành Cặp khóa / Giá trị, do đó chúng tôi có thể truy cập .keyhoặc .valuetương ứng, chúng tôi đang cập nhật (ghi đè) mọi KV-mục .valuevới trường .ipbằng cách sử dụng |=toán tử cập nhật


Giải pháp này là câu trả lời chính xác. Giải pháp đã chọn có các tính năng bổ sung hữu ích nhưng không chính xác hoặc trang nhã. Bạn có thể muốn thêm lời giải thích ngắn gọn và lệnh đầy đủ.
Mike D

Tuyệt vời! Nhiều lần tôi đã sử dụng "to_entries []" chỉ vì tôi không biết cái này.
Lungang Fang
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.