Θα υποθέσουμε ότι είσαι εξοικειωμένος με τη σύνταξη και τους τύπους δεδομένων της JSON.
Το jq λειτουργεί περνώντας τα δεδομένα JSON που έρχονται μέσα από μία μόνο έκφραση (γραμμένη ως σωλήνωση φίλτρων) για να πετύχεις τα επιθυμητά μετασχηματισμένα δεδομένα.
Η γλώσσα jq υλοποιείται από το πρόγραμμα jq.
Αυτό το πρόγραμμα παρέχει αρκετές βολικές επιλογές γραμμής εντολών που ελέγχουν πώς καταναλώνεται η είσοδος και πώς παρουσιάζεται η έξοδος.
Στα παρακάτω παραδείγματα θα συναντήσεις:
-n ή --null-input
Κανονικά, στο πρόγραμμα jq δίνεται ένα αρχείο για ανάγνωση ή στέλνεις δεδομένα στην είσοδό του.
Η επιλογή --null-input σου επιτρέπει να παράγεις δεδομένα JSON χωρίς καμία είσοδο.
-c ή --compact-output
Το jq μορφοποιεί όμορφα την έξοδό του από προεπιλογή.
Είναι εξαιρετικά χρήσιμο για τους ανθρώπους να βλέπουν τα δεδομένα όταν είναι ωραία μορφοποιημένα.
Ωστόσο, αυτό δεν είναι απαραίτητο για τις μηχανές: η επιλογή --compact-output αφαιρεί τα κενά μορφοποίησης για να ελαχιστοποιήσει το μέγεθος του JSON που προκύπτει.
-f filename ή --from-file filename
Διάβασε το πρόγραμμα jq από το filename αντί να το δώσεις στη γραμμή εντολών.
Τόσο το sed όσο και το awk χρησιμοποιούν την επιλογή -f για τον ίδιο σκοπό.
Θα το δεις να χρησιμοποιείται στα scripts δοκιμών για τις ασκήσεις εξάσκησης.
Το υπόλοιπο αυτής της ενότητας θα επικεντρωθεί στη γλώσσα jq.
Τα φίλτρα είναι επίσης γνωστά ως εκφράσεις.
Ένα φίλτρο παίρνει μια είσοδο και παράγει μια έξοδο.
Όπως ακριβώς δουλεύεις σε ένα κέλυφος unix, μπορείς να ενώσεις φίλτρα με έναν σωλήνα | για να συνδέσεις την έξοδο ενός φίλτρου με την είσοδο ενός άλλου.
.
Αυτό είναι το πιο απλό φίλτρο. Απλώς περνάει την είσοδό του στην έξοδό του.
$ echo '[1, 2, 3]' | jq '.'
[
1,
2,
3
]
Αυτή θα είναι μια γρήγορη εισαγωγή στην εργασία με πίνακες. Θα καλύψουμε αυτό το θέμα με περισσότερες λεπτομέρειες αργότερα.
Τα στοιχεία ενός πίνακα προσπελαύνονται με αγκύλες και η αρίθμησή τους ξεκινά από το μηδέν.
$ echo '[10, 20, 30]' | jq '.[1]'
20
Ένα φίλτρο μπορεί να φτιάξει έναν πίνακα τυλίγοντας μια έκφραση μέσα σε [ και ]
με μια γνωστή λίστα στοιχείων:
jq -n '[1, 2, 3]'
για να συλλέξει μια ροή στοιχείων: για παράδειγμα,
το range είναι μια συνάρτηση που παράγει μια ροή αριθμών
$ jq -n 'range(10; 70; 15)'
10
25
40
55
Χρησιμοποιώντας το [] συλλέγεις τα αποτελέσματα της έκφρασης σε έναν πίνακα
$ jq -c -n '[range(10; 70; 15)]'
[10,25,40,55]
Το κόμμα δεν είναι απλώς σύνταξη που χωρίζει στοιχεία πίνακα. Το κόμμα είναι ένας τελεστής που ενώνει ροές.
Για παράδειγμα, το [1, 2, 3] είναι ένα φίλτρο που χρησιμοποιεί τον κατασκευαστή πίνακα [] για να συλλέξει το αποτέλεσμα της ένωσης των τριών εκφράσεων 1, 2 και 3.
Πρόσεξες τις άνω τελείες στο range(10; 70; 15) παραπάνω;
Επειδή τα κόμματα έχουν συγκεκριμένο σκοπό στη γλώσσα jq, οι συναρτήσεις που παίρνουν πολλά ορίσματα χρησιμοποιούν άνω τελείες για να χωρίσουν τα ορίσματα.
Μια γρήγορη εισαγωγή στα αντικείμενα.
Όπως σε πολλές γλώσσες προγραμματισμού, χρησιμοποίησε τελείες για να προσπελάσεις τις ιδιότητες ενός αντικειμένου
$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
Οι αγκύλες μπορούν να χρησιμοποιηθούν και για αντικείμενα, αλλά τότε χρειάζονται εισαγωγικά για τις κυριολεκτικές συμβολοσειρές. Αυτός είναι ένας τρόπος να δουλέψεις με κλειδιά που περιέχουν κενά.
$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"
Μπορείς να κατασκευάσεις ένα αντικείμενο με {} και ζεύγη key: value.
Τα εισαγωγικά δεν απαιτούνται γύρω από κλειδιά που είναι "απλές" συμβολοσειρές.
jq -n '{question: (6 * 9), answer: 42}'
παράγει
{
"question": 54,
"answer": 42
}
Για να αντιμετωπίσεις το κλειδί ως έκφραση, πρέπει να το τυλίξεις σε παρενθέσεις (το παρακάτω επίσης παράγει το ίδιο αποτέλεσμα με πάνω).
echo '[{"key":"question", "value":54}, {"key":"answer", "value":42}]' \
| jq '{(.[0].key): .[0].value, (.[1].key): .[1].value}'
Για παράδειγμα, δίνεται το file.json που περιέχει
{
"key1": "value1",
"key2": [5, 15, 25]
}
Ας υπολογίσουμε το μήκος του πίνακα key2:
$ jq '.key2 | length' file.json
3
Διοχετεύουμε την έξοδο της έκφρασης .key2 ως είσοδο στο length, το οποίο, όπως είναι φυσικό, παράγει τον αριθμό των στοιχείων του πίνακα.
Σε αυτό το παράδειγμα, τα δεδομένα εισόδου JSON αγνοούνται και δεν επηρεάζουν την έξοδο:
$ echo '{"answer": 42}' | jq '6 * 9'
54
Ένα φίλτρο μπορεί να παράγει περισσότερες από μία τιμές.
Για παράδειγμα, το φίλτρο .[] παράγει κάθε στοιχείο ενός πίνακα ως ξεχωριστή τιμή:
$ jq -n -c '[1, 2, 3]'
[1,2,3]
$ jq -n -c '[1, 2, 3] | .[]'
1
2
3
Η διοχέτευση ενός τέτοιου φίλτρου σε ένα άλλο θα εκτελέσει το δεύτερο φίλτρο για κάθε τιμή:
$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6
Αυτό μοιάζει με σιωπηρή επανάληψη.
Μόλις καταλάβεις αυτή την τεχνική, θα συνειδητοποιήσεις ότι πολύ ισχυρά φίλτρα jq μπορούν να είναι πολύ συνοπτικά.
Οι παρενθέσεις χρησιμοποιούνται για να ομαδοποιήσουν υποεκφράσεις και να επιβάλουν τη σειρά των πράξεων, όπως ακριβώς σε άλλες γλώσσες.
Στο jq, η ανάγκη γι' αυτές μπορεί να φαίνεται κάπως αναπάντεχη.
Για παράδειγμα, ας υποθέσουμε ότι θέλουμε να κατασκευάσουμε έναν πίνακα με 2 στοιχεία: την τετραγωνική ρίζα του 9 και το e υψωμένο στη δύναμη 1.
Οι δύο επιμέρους εκφράσεις είναι 9 | sqrt και 1 | exp.
Περιμένουμε η έξοδος να είναι ο πίνακας [3, 2.7...]
$ jq -n '[ 9|sqrt, 1|exp ]'
[
20.085536923187668,
2.718281828459045
]
Γιατί δεν πήραμε αυτό που περιμέναμε; Το jq το ερμηνεύει ως εξής:
[ ((9|sqrt), 1) | exp ]
Το jq φτιάχνει μια ροή δύο στοιχείων (3 και 1), τα οποία δίνονται το καθένα στο exp.
Πρέπει να διασφαλίσουμε ότι το exp παίρνει μόνο έναν αριθμό ως είσοδο.
Με άλλα λόγια, πρέπει να επιβάλουμε ο σωλήνας να αξιολογείται πριν από το κόμμα.
$ jq -n '[ 9|sqrt, (1|exp) ]'
[
3,
2.718281828459045
]
Χωρίς να μπούμε σε μεγάλο βάθος (οι συναρτήσεις θα είναι θέμα για άλλη άσκηση), ορίστε μερικές χρήσιμες ενσωματωμένες συναρτήσεις:
length
Με έναν πίνακα ως είσοδο, παράγει τον αριθμό των στοιχείων του πίνακα.
$ jq -n '[10, 20, 30, 40] | length'
4
+
Αυτός ο τελεστής κάνει διαφορετικά πράγματα ανάλογα με τον τύπο των τελεστέων του: προσθέτει αριθμούς, συνενώνει συμβολοσειρές, προσαρτά πίνακες, συγχωνεύει αντικείμενα.
$ jq -c -n '
3 + 4,
"foo" + "bar",
["a", "b"] + ["c"],
{"m": 10} + {"n": 20}
'
7
"foobar"
["a","b","c"]
{"m":10,"n":20}
Το add είναι μια συνάρτηση που παίρνει έναν πίνακα και επιστρέφει ένα στοιχείο με όλα τα στοιχεία αθροισμένα σύμφωνα με τους κανόνες του +.
Το [1, 2, 3] | add παράγει 6.
map
Με έναν πίνακα ως είσοδο και ένα φίλτρο ως όρισμα, παράγει έναν πίνακα όπου το φίλτρο εφαρμόζεται σε κάθε στοιχείο
$ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
[2,4,6,8]
select
Με κάποια είσοδο και ένα φίλτρο ως όρισμα:
null, πραγματικά καμία έξοδο)Για παράδειγμα, δίνονται κάποιοι αριθμοί, διάλεξε αυτούς που διαιρούνται με το 3
$ jq -n 'range(10) | select(. % 3 == 0)'
0
3
6
9
Θυμήσου ότι το range παράγει μια ροή αριθμών.
Το select θα καλείται μία φορά για κάθε αριθμό.
Παράγονται μόνο οι αριθμοί που "περνούν" την έκφραση.
Συχνά χρειάζεται να διαλέξεις στοιχεία ενός πίνακα. Υπάρχουν μερικοί τρόποι να το κάνεις αυτό.
Με είσοδο ["Anne", "Bob", "Cathy", "Dave"], διάλεξε τα ονόματα που έχουν μήκος 4.
χρησιμοποίησε το map και το select μαζί
map(select(length == 4))
σπάσε τον πίνακα στα στοιχεία του, εφάρμοσε select σε αυτή τη ροή και μάζεψε τα αποτελέσματα
[ .[] | select(length == 4) ]
Τα σχόλια ξεκινούν με τον χαρακτήρα # και συνεχίζουν μέχρι το τέλος της γραμμής.
Έχεις ξαφνικά μια λιγούρα για τηγανίτες. Ως σύγχρονος άνθρωπος με τεχνικές κλίσεις, γράφεις μια λίστα αγορών για τα υλικά των τηγανιτών σε μορφή JSON. Η δομή της λίστας είναι:
{
"name": "name of shopping list",
"ingredients": [ ...list of ingredients... ],
"optional ingredients": [ ...list of ingredients... ]
}
Ένα υλικό αναπαρίσταται ως αντικείμενο JSON, όπως:
{
"item": "flour",
"amount": {
"quantity": 2,
"unit": "cup"
}
}
Ένα υλικό έχει μια προαιρετική ιδιότητα με όνομα "substitute" που περιέχει μια
συμβολοσειρά με ένα άλλο υλικό που μπορεί να χρησιμοποιηθεί στη θέση του.
Ας δούμε πώς μπορούμε να εξετάσουμε τη λίστα αγορών με το jq
Γράψε μια έκφραση που να βγάζει το στοιχείο "name" της λίστας αγορών.
Μέτρησε μόνο τα υποχρεωτικά υλικά. Μη συμπεριλάβεις τα προαιρετικά υλικά.
Γράψε μια έκφραση που να βγάζει την ποσότητα ζάχαρης. Θέλουμε μόνο το αριθμητικό μέρος.
Μερικά από τα υλικά μπορούν να αντικατασταθούν (αν δεν έχεις το υλικό X, μπορείς να χρησιμοποιήσεις το Y). Βγάλε ένα αντικείμενο JSON που αντιστοιχίζει το συνιστώμενο υλικό με το υποκατάστατό του. Συμπεριλάβε τα προαιρετικά υλικά στην αντιστοίχιση.
Γράψου στο Exercism για να μάθεις και να κατακτήσεις jq με 12 έννοιες75 ασκήσεις και πραγματική καθοδήγηση από ανθρώπους, όλα δωρεάν.