| FQ(1) | FQ | FQ(1) |
NAME¶
fq - tool, language and decoders for working with binary formats
SYNOPSIS¶
fq [OPTIONS] [--] [EXPRESSION] [FILE...]
DESCRIPTION¶
fq is a tool, language, and set of decoders for working with binary formats and data. In most cases it behaves and feels similar to jq <https://jqlang.github.io/jq/> and it also uses the same expression language. To get the most out of fq it’s recommended to learn more about jq.
It features a structural hex viewer, nested format decoding, slicing and concatenating binary data, bit-level decoding and an interactive REPL with auto-completion.
# Evaluate "d" (display) for file.mp4 $ fq d file.mp4 # structural hex output # Evaluate "da" (display all) for file.mp4 $ fq da file.mp4 # structural hex output # JSON for file.mp4 $ fq -V . file.mp4 # JSON output # Evaluate ".boxes[0].type" for all *.mp4 files # -Vr to output value without quotes $ fq -Vr '.boxes[0].type' *.mp4 ftyp # Evaluate "1+2" without reading any input $ fq -n 1+2 3
For more usage examples see the examples section at the end of the documentation.
OPTIONS¶
--arg NAME VALUE
--argdecode NAME PATH
--argjson NAME JSON
--args
--color-output, -C
--compact-output, -c
--decode, -d NAME
--from-file, -f PATH
--help, -h [TOPIC]
--include-path, -L PATH
--join-output, -j
--jsonargs
--monochrome-output, -M
--null-input, -n
--option, -o NAME=VALUE/@PATH
-o addrbase=number
-o array_truncate=number
-o bits_format=string
-o bits_format=base64
-o bits_format=byte_array
-o bits_format=hex
-o bits_format=md5
-o bits_format=snippet
-o bits_format=string
-o bits_format=truncate
-o byte_colors=ranges=string,...
-o color=true|false
-o colors=key=value,...
-o compact=true|false
-o completion_timeout=number
-o depth=number
-o display_bytes=number
-o force=true|false
-o join_string=string
-o line_bytes=number
-o raw_string=true|false
-o sizebase=number
-o skip_gaps=true|false
-o string_truncate=number
-o unicode=true|false
-o verbose=true|false
-o width=number
--raw-file NAME PATH
--raw-input, -R
--raw-output, -r
--raw-output0
--repl, -i
--slurp, -s
--unicode-output, -U
--value-output, -V
--version, -v
CONFIGURATION¶
Init files¶
To add your own functions you can use init.jq that is read from:
macOS
$HOME/.config/fq/init.jq
Linux and BSD
Windows
Environment¶
NO_COLOR
CLIUNICODE
COMPLETION_TIMEOUT
NO_DECODE_PROGRESS
EXIT STATUS¶
0
Success
2 Argument error or
input IO error
3 Expression compile
error
4 Decode error
5 Expression
error
EXPRESSION¶
Syntax¶
See jq(1) for syntax details. But here are some common beginner gotchas:
Additional features¶
fq uses an extended variant of the jq language with a few extra features:
`hello \("world")\ud83c\udf0d`
results in the string hello \("world")\ud83c\udf0d or as JSON "hello \\(\"world\")\\ud83c\\udf0d". In contrast
"hello \("world")\ud83c\udf0d"
results in the string hello world🌍 or as JSON "hello world🌍".
Additional functions¶
band, bor, bxor, bsl, bsr, bnot
chunk($size)
count, count_by(f)
delta, delta_by(f)
diff($a; $b)
expr_to_path
grep_by(f)
group
path_to_expr
paste
streaks, streaks_by(f)
repl, repl($opts)
slurp("<name>")
spew, spew("<name>")
println, print
printerrln, printerr
hexdump, hexdump($opts), hd, hd($opts)
format
Decode value¶
A decode value is the type returned from decoding a format and used to represent values produced by a decoder. It can be seen as representing any standard jq type but with some additional properties attached.
Each decode value has these properties:
The value of a decode value is the symbolic value if available and otherwise the actual value. To explicitly access the value use tovalue. In most expressions this is not needed as it will be done automatically.
Decode value functions¶
root
buffer_root
format_root
parent
parents
topath
tovalue, tovalue($opts)
toactual, toactual($opts)
tosym, tosym($opts)
todescription
torepr
decode, decode($name), decode($name; $opts)
tobytes, tobytesrange, tobits and tobitsrange on a decode value will return the raw source bits as a binary.
Binary¶
Binary type is used to store raw bits or bytes. Raw bits will act as zero bits padded strings in standard jq expressions.
Use tobits and tobytes to create them from decode value, string, number or binary array. tobytes will if needed zero pad most significant bits to be byte aligned.
There is also tobitsrange and tobytesrange which do the same thing but will preserve source range when displayed.
Binary functions¶
grep($v), grep($v; $flags), vgrep($v), vgrep($v; $flags), bgrep($v), bgrep($v; $flags)
fgrep($v), fgrep($v; $flags)
tobits
tobitsrange
tobytes
tobytesrange
open
The standard jq functions test, match, capture, scan and split also work on binary values, matching against the raw bytes.
Binary array¶
Binary array is a value "shape" and not a new type. It’s an array of numbers, strings, binaries or other binary arrays. They can be used as input to tobits, tobytes or other functions that accept a binary as input.
Binary arrays are similar to and inspired by Erlang iolist <https://www.erlang.org/doc/man/erlang.html#type-iolist>.
Some examples:
Differences to jq¶
See gojq’s differences to jq <https://github.com/itchyny/gojq#difference-to-jq>.
Naming inconsistencies¶
jq’s naming convention is a bit inconsistent. Some standard library functions are named tojson while others from_entries. fq follows this tradition but tries to use snake_case unless there is a good reason.
Here are all the non-snake_case functions added by fq. Most of them deal with decode and binary values which are new "primitive" types:
DISPLAY OUTPUT¶
display or d is the main function for displaying values and is also the function that will be used if no other output function is explicitly used. If its input is a decode value it will output a dump and tree structure or otherwise it will output as JSON.
Below are some usage examples:
The first and second examples do the same thing, inputting "hello" to display.
$ fq -n '"hello"' "hello" $ fq -n '"hello" | d' "hello"
In the next few examples we select out the first "edit list" box in an mp4 file and display it in various ways.
By default, display will only show the root level:
$ fq 'first(grep_by(.type == "elst"))' file.mp4
|00 01 02 03 04 05 06 07 08 09|0123456789|.boxes[3].boxes[1].boxes[1].boxes[0]{}: box 0xd5c| 00| .| size: 28 0xd66|00 00 1c |... | 0xd66| 65 6c 73 74 | elst | type: "elst" (An edit list) 0xd66| 00 | . | version: 0 0xd66| 00 00| ..| flags: 0 0xd70|00 |. | 0xd70| 00 00 00 01 | .... | entry_count: 1 0xd70| 00 00 00 28 00| ...(.| entries[0:1]: 0xd7a|00 00 00 00 01 00 00 |....... |
First row shows a ruler with byte offset into the line and jq path for the value.
The columns are:
Notation:
With display or d it will recursively show the whole tree:
$ fq 'first(grep_by(.type == "elst")) | d' file.mp4
|00 01 02 03 04 05 06 07 08 09|0123456789|.boxes[3].boxes[1].boxes[1].boxes[0]{}: box 0xd5c| 00| .| size: 28 0xd66|00 00 1c |... | 0xd66| 65 6c 73 74 | elst | type: "elst" (An edit list) 0xd66| 00 | . | version: 0 0xd66| 00 00| ..| flags: 0 0xd70|00 |. | 0xd70| 00 00 00 01 | .... | entry_count: 1
| | | entries[0:1]:
| | | [0]{}: entry 0xd70| 00 00 00 28 | ...( | segment_duration: 40 0xd70| 00| .| media_time: 0 0xd7a|00 00 00 |... | 0xd7a| 00 01 00 00 | .... | media_rate: 1
Same but verbose dv:
$ fq 'first(grep_by(.type == "elst")) | dv' file.mp4
|00 01 02 03 04 05 06 07 08 09|0123456789|.boxes[3].boxes[1].boxes[1].boxes[0]{}: box 0xd65-0xd81 (28) 0xd5c| 00| .| size: 28 0xd65-0xd69 (4) 0xd66|00 00 1c |... | 0xd66| 65 6c 73 74 | elst | type: "elst" (An edit list) 0xd69-0xd6d (4) 0xd66| 00 | . | version: 0 0xd6d-0xd6e (1) 0xd66| 00 00| ..| flags: 0 0xd6e-0xd71 (3) 0xd70|00 |. | 0xd70| 00 00 00 01 | .... | entry_count: 1 0xd71-0xd75 (4)
| | | entries[0:1]: 0xd75-0xd81 (12)
| | | [0]{}: entry 0xd75-0xd81 (12) 0xd70| 00 00 00 28 | ...( | segment_duration: 40 0xd75-0xd79 (4) 0xd70| 00| .| media_time: 0 0xd79-0xd7d (4) 0xd7a|00 00 00 |... | 0xd7a| 00 01 00 00 | .... | media_rate: 1 0xd7d-0xd81 (4)
In verbose mode bit ranges and array element names are shown.
Bit ranges use <start-byte>[.<bits>]-<end-byte>[.<bits>] as notation where .<bits> is left out if byte aligned. For example type starts at byte 0xd69 bit 0 (.0 is left out) and ends at 0xd6d bit 0 (exclusive) and has a size of 4 bytes.
This verbosely displays the header of the second frame in an mp3 file which has a bunch of non-byte-aligned fields:
$ fq '.frames[1].header | dv' file.mp3
|00 01 02 03 04 05 06 07 08 09|0123456789|.frames[1].header{}: 0xb79-0xb7d (4) 0xb72| ff fb | .. | sync: 0b11111111111 (valid) 0xb79-0xb7a.3 (1.3) 0xb72| fb | . | mpeg_version: "1" (3) (MPEG Version 1) 0xb7a.3-0xb7a.5 (0.2) 0xb72| fb | . | layer: 3 (1) (MPEG Layer 3) 0xb7a.5-0xb7a.7 (0.2)
| | | sample_count: 1152 0xb72| fb | . | protection_absent: true (No CRC) 0xb7a.7-0xb7b (0.1) 0xb72| 50| P| bitrate: 64000 (5) 0xb7b-0xb7b.4 (0.4) 0xb72| 50| P| sample_rate: 44100 (0) 0xb7b.4-0xb7b.6 (0.2) 0xb72| 50| P| padding: "not_padded" (0b0) 0xb7b.6-0xb7b.7 (0.1) 0xb72| 50| P| private: 0 0xb7b.7-0xb7c (0.1) 0xb7c|c4 |. | channels: "mono" (0b11) 0xb7c-0xb7c.2 (0.2) 0xb7c|c4 |. | channel_mode: "none" (0b0) 0xb7c.2-0xb7c.4 (0.2) 0xb7c|c4 |. | copyright: 0 0xb7c.4-0xb7c.5 (0.1) 0xb7c|c4 |. | original: 1 0xb7c.5-0xb7c.6 (0.1) 0xb7c|c4 |. | emphasis: "none" (0b0) 0xb7c.6-0xb7d (0.2)
Here the sync pattern starts at 0xb79 (bit 0) and ends at 0xb7a.3 (exclusive) and has a size of 1 byte and 3 bits, 11 bits in total (8+3).
There are also some other display aliases:
FORMATS¶
By default fq will try to automatically determine input format. In some cases this might fail or is not possible, then a format can be specified using -d NAME. It’s possible sometimes to force decode and get a partial or broken result using -o force=true.
# decode as msgpack $ fq -d msgpack d file # force decode as msgpack $ fq -d msgpack -o force=true d file # see msgpack format help $ fq -h msgpack # list supported formats $ fq -h formats
Format options¶
Some formats have their own options that can be set using -o. For example the mp4 format has a decode_samples option that controls if individual samples should be decoded. To disable it one can do fq -o decode_samples=false . file.mp4. See format list for options.
Format functions¶
In addition to using -d all format decoders are also available as normal jq functions. Each format provides multiple functions:
<name>
<name>($options)
from_<name>
from_<name>($options)
Example usage:
# decode jpeg found inside some other format $ fq '.some[].query | jpeg' file # decode jpeg at byte range 100-200 $ fq -d bytes '.[100:200] | jpeg' file
Supported formats¶
aac_frame
Options
-o object_type=1
adts
adts_frame
aiff
amf0
apev2
apple_bookmark
Apple’s bookmarkData format is used to encode information that can be resolved into a URL object for a file even if the user moves or renames it. Can also contain security scoping information for App Sandbox support. These bookmarkData blobs are often found encoded in data fields of Binary Property Lists. Notable examples include:
The grep_by function can be used to recursively descend through the decoded tree, probing for and selecting any bookmark blobs, then converting them to readable JSON with torepr:
fq 'grep_by(.type=="data" and .value[0:4] == "book") | .value | apple_bookmark | torepr' <sfl2 file>
Authors
References
ar
asn1_ber
Supports decoding BER, CER and DER (X.690).
Can be used to decode certificates etc
$ fq -d bytes 'from_pem | asn1_ber | d' cert.pem
Can decode nested values
$ fq -d asn1_ber '.constructed[1].value | asn1_ber' file.ber
Manual schema
$ fq -d asn1_ber 'torepr as $r | ["version", "modulus", "private_exponent", "prime1", "prime2", "exponent1", "exponent2", "coefficient"] | with_entries({key: .value, value: $r[.key]})' pkcs1.der
References
av1_ccr
av1_frame
av1_obu
avc_annexb
avc_au
Options
-o bottom_field_pic_order_in_frame_present_flag=false
-o cpb_cnt=0
-o cpb_removal_delay_length=0
-o delta_pic_order_always_zero_flag=false
-o dpb_output_delay_length=0
-o frame_mbs_only_flag=true
-o initial_cpb_removal_delay_length=0
-o length_size=0
-o log2max_frame_num=4
-o log2max_pic_order_cnt_lsb=4
-o nal_hrd_parameters_present=false
-o pic_order_cnt_type=0
-o redundant_pic_cnt_present_flag=false
-o separate_colour_plane_flag=false
-o time_offset_length=0
-o vcl_hrd_parameters_present=false
avc_dcr
avc_nalu
Options
-o bottom_field_pic_order_in_frame_present_flag=false
-o cpb_cnt=0
-o cpb_removal_delay_length=0
-o delta_pic_order_always_zero_flag=false
-o dpb_output_delay_length=0
-o frame_mbs_only_flag=true
-o initial_cpb_removal_delay_length=0
-o log2max_frame_num=4
-o log2max_pic_order_cnt_lsb=4
-o nal_hrd_parameters_present=false
-o pic_order_cnt_type=0
-o redundant_pic_cnt_present_flag=false
-o separate_colour_plane_flag=false
-o time_offset_length=0
-o vcl_hrd_parameters_present=false
avc_pps
avc_sei
Options
-o cpb_cnt=0
-o cpb_removal_delay_length=0
-o delta_pic_order_always_zero_flag=false
-o dpb_output_delay_length=0
-o frame_mbs_only_flag=true
-o initial_cpb_removal_delay_length=0
-o log2max_frame_num=4
-o log2max_pic_order_cnt_lsb=4
-o nal_hrd_parameters_present=false
-o pic_order_cnt_type=0
-o separate_colour_plane_flag=false
-o time_offset_length=0
-o vcl_hrd_parameters_present=false
avc_sps
avi
Samples
Extract samples for stream 1
$ fq '.streams[1].samples[] | tobytes' file.avi > stream01.mp3
Show stream summary
$ fq -o decode_samples=false '[.chunks[0] | grep_by(.id=="LIST" and .type=="strl") | grep_by(.id=="strh") as {$type} | grep_by(.id=="strf") as {$format_tag, $compression} | {$type,$format_tag,$compression}]' *.avi
Speed up decoding by disabling sample and extended chunks decoding
$ fq -o decode_samples=false -o decode_extended_chunks=false d file.avi
References
Options
-o decode_extended_chunks=true
-o decode_samples=true
avro_ocf
Supports reading Avro Object Container Format (OCF) files based on the 1.11.0 specification. Capable of handling null, deflate, and snappy codecs for data compression. Limitations:
References
Authors
bencode
Convert represented value to JSON
$ fq -d bencode torepr file.torrent
References
bitcoin_blkdat
bitcoin_block
Options
-o has_header=false
bitcoin_script
bitcoin_transaction
bits
Decode to a slice and indexable binary of bits.
Slice and decode bit range
$ echo 'some {"a":1} json' | fq -d bits '.[40:-48] | fromjson'
{
"a": 1
}
Index bits
$ echo 'hello' | fq -d bits '.[4]' 1 $ echo 'hello' | fq -c -d bits '[.[range(8)]]' [0,1,1,0,1,0,0,0]
bplist
Show full decoding
$ fq d Info.plist
Timestamps
$ fq 'torepr.SomeTimeStamp | tovalue' Info.plist 685135328 $ fq 'torepr.SomeTimeStamp | todescription' Info.plist "2022-09-17T19:22:08Z"
Get JSON representation
$ fq torepr com.apple.UIAutomation.plist
{
"UIAutomationEnabled": true
}
Decoding NSKeyedArchiver serialized objects
# Assume $top.root is present bplist> from_ns_keyed_archiver # Specify optional root bplist> from_ns_keyed_archiver(1)
Authors
References
bsd_loopback_frame
bson
Limitations
Convert represented value to JSON
$ fq -d bson torepr file.bson
Filter represented value
$ fq -d bson 'torepr | select(.name=="bob")' file.bson
Authors
References
bytes
Decode to a slice and indexable binary of bytes.
Slice out byte ranges
$ echo -n 'hello' | fq -d bytes '.[-3:]' > last_3_bytes $ echo -n 'hello' | fq -d bytes '[.[-2:], .[0:2]] | tobytes' > first_last_2_bytes_swapped
Slice and decode byte range
$ echo 'some {"a":1} json' | fq -d bytes '.[5:-6] | fromjson'
{
"a": 1
}
Index bytes
$ echo 'hello' | fq -d bytes '.[1]' 101
bzip2
caff
Authors
Options
-o uncompress=true
cbor
Convert represented value to JSON
$ fq -d cbor torepr file.cbor
References
csv
TSV to CSV
$ fq -d csv -o comma="\t" to_csv file.tsv
Convert rows to objects based on header row
$ fq -d csv '.[0] as $t | .[1:] | map(with_entries(.key = $t[.key]))' file.csv
Options
-o comma=","
-o comment="#"
dns
dns_tcp
elf
ether8023_frame
exif
fairplay_spc
fit
Limitations
Convert stream of data messages to JSON array
$ fq '[.data_records[] | select(.record_header.message_type == "data").data_message]' file.fit
Authors
References
flac
flac_frame
Options
-o bits_per_sample=16
-o sample_details=false
flac_metadatablock
flac_metadatablocks
flac_picture
flac_streaminfo
gif
gzip
heif
Options
-o allow_truncated=false
hevc_annexb
hevc_au
Options
-o length_size=4
hevc_dcr
hevc_nalu
hevc_pps
hevc_sps
hevc_vps
html
HTML is decoded in HTML5 mode and will always include <html>, <body> and <head> elements. See xml format for more examples and how to preserve element order and how to encode to xml. There is no to_html function, see to_xml instead.
Element as object
# decode as object is the default
$ echo '<a href="url">text</a>' | fq -d html
{
"html": {
"body": {
"a": {
"#text": "text",
"@href": "url"
}
},
"head": ""
}
}
Element as array
$ echo '<a href="url">text</a>' | fq -d html -o array=true [
"html",
null,
[
[
"head",
null,
[]
],
[
"body",
null,
[
[
"a",
{
"#text": "text",
"href": "url"
},
[]
]
]
]
] ] # decode html files to a {file: "title", ...} object $ fq -n -d html '[inputs | {key: input_filename, value: .html.head.title?}] | from_entries' *.html # <a> href:s in file $ fq -r -o array=true -d html '.. | select(.[0] == "a" and .[1].href)?.[1].href' file.html
Options
-o array=false
-o attribute_prefix="@"
-o seq=false
icc_profile
icmp
icmpv6
id3v1
id3v11
id3v2
ipv4_packet
ipv6_packet
jp2c
jpeg
json
jsonl
leveldb_descriptor
Limitations
Authors
References
leveldb_log
Limitations
Authors
References
leveldb_table
Limitations
Authors
References
luajit
macho
Supports decoding vanilla and FAT Mach-O binaries.
Select 64bit load segments
$ fq '.load_commands[] | select(.cmd=="segment_64")' file
References
Authors
macho_fat
markdown
Array with all level 1 and 2 headers
$ fq -d markdown '[.. | select(.type=="heading" and .level<=2)?.children[0]]' file.md
matroska
Lookup element using path
$ fq 'matroska_path(".Segment.Tracks[0]")' file.mkv
Get path to element
$ fq 'grep_by(.id == "Tracks") | matroska_path' file.mkv
References
Options
-o decode_samples=true
midi
Notes
Sample queries
fq -d midi '.. | select(.event=="track_name")? | "\(.track_name)"' midi/twinkle.mid
fq -d midi '.. | select(.event=="tempo")?.tempo' midi/twinkle.mid
fq -d midi '.. | select(.event=="key_signature")?.key_signature' midi/twinkle.mid
fq -d midi 'grep_by(.event=="note_on") | [.time.tick, .note_on.note] | join(" ")' midi/twinkle.mid
Authors
References
moc3
Authors
mp3
Options
-o max_sync_seek=32768
-o max_unique_header_configs=5
-o max_unknown=50
mp3_frame
mp3_frame_vbri
mp3_frame_xing
mp4
Speed up decoding by not decoding samples
# manually decode first sample as an aac_frame $ fq -o decode_samples=false '.tracks[0].samples[0] | aac_frame | d' file.mp4
Entries for first edit list as values
$ fq 'first(grep_by(.type=="elst").entries) | tovalue' file.mp4
Whole box tree as JSON (exclude mdat data and tracks)
$ fq 'del(.tracks) | grep_by(.type=="mdat").data = "<excluded>" | tovalue' file.mp4
Force decode a single box
$ fq -n '"AAAAHGVsc3QAAAAAAAAAAQAAADIAAAQAAAEAAA==" | from_base64 | mp4({force:true}) | d'
Lookup mp4 box using an mp4 box path
# <decode value box> | mp4_path($path) -> <decode value box>
$ fq 'mp4_path(".moov.trak[1]")' file.mp4
Get mp4 box path for a decode value box
# <decode value box> | mp4_path -> string $ fq 'grep_by(.type == "trak") | mp4_path' file.mp4
References
Options
-o allow_truncated=false
-o decode_samples=true
-o skip_samples=false
mpeg_asc
mpeg_es
mpeg_pes
mpeg_pes_packet
mpeg_spu
mpeg_ts
msgpack
Convert represented value to JSON
$ fq -d msgpack torepr file.msgpack
References
negentropy
View a full Negentropy message
$ fq -d negentropy dd file
Or from hex
$ echo '6186b7abb47c0001108e4206828ee3bf34258465809a337c6c00019a68e37b177a50b3ae7164ccc628b962020114019c1381281c9e3849d5fbd514b7bb65ad0101e601fbf7451f5d22e7fa36ae3e910e9f5215020157014a1b26853e06e9c32eb41b1df4f9ab300201e6011840e273c84bb1344f1d4e15d9aa67920200016f12ee2340888653f10b0ec2d438ac9f0101840156d2d796f4dff004ab369b9bcfa4d81e020187013f1b3c8a019800d5764e2de6bdfd2785020114017caaf0acb5dfe249aa0f7f742402168a01018301e7b8c4decb1eae455ca5714281e3245302017a01409c22636b097362df125ddffb6d944302015b01f332208bee82acf8ed922853ee54057f020001fc3e51fdb0b92966e38017f7959903850101cc01428ce0c96d49f15b50143e4fb228cb9300000131712d30e5296a7a45d07bba452d61cd' | fq -R 'from_hex | negentropy | dd'
Check how many ranges the message has and how many of those are of 'fingerprint' mode
$ fq -d negentropy '.bounds | length as $total | map(select(.mode == "fingerprint")) | length | {$total, fingerprint: .}' message
Get all ids in all idlists
$ fq -d negentropy '.bounds | map(select(.mode == "idlist") | .idlist | .ids) | flatten' message
Authors
References
nes
Limitations
Decompile PRG ROM
$ fq -r '.prg_rom[] | nes_toasm' file.nes
Print out first CHR ROM tile in Kitty (or Konsole, wayst, WezTerm) at size 5
$ printf $(fq -r -d nes '.chr_rom[0] | nes_tokitty(5)' file.nes)
Print out all CHR ROM tiles in Kitty (with Bash) at size 5
$ for line in $(fq -r '.chr_rom[] | nes_tokitty(5)' file.nes);do printf "%b%s" "$line";done
Authors
References
ogg
ogg_page
opentimestamps
View a full OpenTimestamps file
$ fq dd file.ots
List the names of the Calendar servers used
$ fq '.operations | map(select(.attestation_type == "calendar") | .url)' file.ots
Check if there are Bitcoin attestations present
$ fq '.operations | map(select(.attestation_type == "bitcoin")) | length > 0' file.ots
Authors
References
opus_packet
pcap
Build object with number of (reassembled) TCP bytes sent to/from client IP
# for a pcapng file you would use .[0].tcp_connections for first section
$ fq '.tcp_connections | group_by(.client.ip) | map({key: .[0].client.ip, value: map(.client.stream, .server.stream | tobytes.size) | add}) | from_entries'
{
"10.1.0.22": 15116,
"10.99.12.136": 234,
"10.99.12.150": 218
}
pcapng
pg_btree
Btree index meta page
$ fq -d pg_btree -o flavour=postgres14 ".[0] | d" 16404
Btree index page
$ fq -d pg_btree -o flavour=postgres14 ".[1]" 16404
Authors
References
Options
-o page=0
pg_control
Decode content of pg_control file
$ fq -d pg_control -o flavour=postgres14 d pg_control
Specific fields can be queried individually
$ fq -d pg_control -o flavour=postgres14 ".state, .check_point_copy.redo, .wal_level" pg_control
Authors
References
Options
-o flavour=""
pg_heap
To see heap page’s content
$ fq -d pg_heap -o flavour=postgres14 ".[0]" 16994
To see page’s header
$ fq -d pg_heap -o flavour=postgres14 ".[0].page_header" 16994
First and last item pointers on first page
$ fq -d pg_heap -o flavour=postgres14 ".[0].pd_linp[0, -1]" 16994
First and last tuple on first page
$ fq -d pg_heap -o flavour=postgres14 ".[0].tuples[0, -1]" 16994
Authors
References
Options
-o flavour="postgres14"
-o page=0
-o segment=0
png
prores_frame
protobuf
Can decode sub messages
$ fq -d protobuf '.fields[6].wire_value | protobuf | d' file
References
protobuf_widevine
pssh_playready
rtmp
Currently only supports plain RTMP (not RTMPT or encrypted variants etc) with AMF0 (not AMF3).
Show rtmp streams in PCAP file
fq '.tcp_connections[] | select(.server.port=="rtmp") | d' file.cap
References
safetensors
sll2_packet
sll_packet
stl
Decode binary STL (Stereolithography, Standard Tessellation Language) files.
Current limitations
tap
The TAP- (and BLK-) format is nearly a direct copy of the data that is stored in real tapes, as it is written by the ROM save routine of the ZX-Spectrum. A TAP file is simply one data block or a group of 2 or more data blocks, one followed after the other. The TAP file may be empty. You will often find this format embedded inside the TZX tape format. The default file extension is .tap.
Processing JSON files
fq -o bits_format=byte_array -d tap -V d /path/to/file.tap
Authors
References
tar
tcp_segment
tiff
tls
Supports decoding of most standard records, messages and extensions. Can also decrypt most standard cipher suites in a PCAP with traffic in both directions if an NSS key log is provided.
Decode and decrypt providing a PCAP and key log
$ tcpdump -i <iface> -w traffic.pcap
Make sure your curl TLS backend supports SSLKEYLOGFILE and do:
$ SSLKEYLOGFILE=traffic.keylog curl --tls-max 1.2 https://host/path
Decode, decrypt and query. Uses keylog=@<path> to read option value from keylog file:
# decode and show whole tree $ fq -o keylog=@traffic.keylog d traffic.pcap # write unencrypted server response to a file. # first .stream is the TCP stream, second .stream is TLS application data stream # # first TCP connections: $ fq -o keylog=@traffic.keylog '.tcp_connections[0].server.stream.stream | tobytes' traffic.pcap > data # first TLS connection: $ fq -o keylog=@traffic.keylog 'first(grep_by(.server.stream | format == "tls")).server.stream.stream | tobytes' > data
Supported cipher suites for decryption
References
Options
-o keylog=""
toml
tzif
Get last transition time
fq '.v2plusdatablock.transition_times[-1] | tovalue' tziffile
Count leap second records
fq '.v2plusdatablock.leap_second_records | length' tziffile
Authors
References
tzx
TZX is a file format designed to preserve cassette tapes compatible with the ZX Spectrum computers, although some specialized versions of the format have been defined for other machines such as the Amstrad CPC and C64. The format was originally created by Tomaz Kac, who was the maintainer until revision 1.13, before passing it to Martijn v.d. Heide. For a brief period the company Ramsoft became the maintainers, and created revision v1.20. The default file extension is .tzx.
Processing JSON files
fq -o bits_format=byte_array -d tzx -V d /path/to/file.tzx
Authors
References
udp_datagram
vorbis_comment
vorbis_packet
vp8_frame
vp9_cfm
vp9_frame
vpx_ccr
wasm
Count opcode usage
$ fq '.sections[] | select(.id == "code_section") | [.. | .opcode? // empty] | count | map({key: .[0], value: .[1]}) | from_entries' file.wasm
List exports and imports
$ fq '.sections | {import: map(select(.id == "import_section").content.im.x[].nm.b), export: map(select(.id == "export_section").content.ex.x[].nm.b)}' file.wasm
Authors
References
wav
webp
xml
XML can be decoded and encoded into jq values in two ways, elements as object or array. The object variant might be easier to query for a specific value but array might be easier to use to generate xml or to query after all elements of some kind etc. Encoding is done using the to_xml function and it will figure out what variant is used based on the input value. It has two optional options indent and attribute_prefix.
Elements as object
If there is #seq attribute it encodes the child element order. Use -o seq=true to include sequence number when decoding, otherwise order might be lost.
# decode as object is the default
$ echo '<a><b/><b>bbb</b><c attr="value">ccc</c></a>' | fq -d xml -o seq=true
{
"a": {
"b": [
{
"#seq": 0
},
{
"#seq": 1,
"#text": "bbb"
}
],
"c": {
"#seq": 2,
"#text": "ccc",
"@attr": "value"
}
}
}
# access text of the <c> element
$ echo '<a><b/><b>bbb</b><c attr="value">ccc</c></a>' | fq '.a.c["#text"]'
"ccc"
# decode to object and encode to xml
$ echo '<a><b/><b>bbb</b><c attr="value">ccc</c></a>' | fq -r -d xml -o seq=true 'to_xml({indent:2})'
<a>
<b></b>
<b>bbb</b>
<c attr="value">ccc</c>
</a>
Elements as array
# decode as array $ echo '<a><b/><b>bbb</b><c attr="value">ccc</c></a>' | fq -d xml -o array=true [
"a",
null,
[
[
"b",
null,
[]
],
[
"b",
{
"#text": "bbb"
},
[]
],
[
"c",
{
"#text": "ccc",
"attr": "value"
},
[]
]
] ] # decode to array and encode to xml $ echo '<a><b/><b>bbb</b><c attr="value">ccc</c></a>' | fq -r -d xml -o array=true -o seq=true 'to_xml({indent:2})' <a>
<b></b>
<b>bbb</b>
<c attr="value">ccc</c> </a> # access text of the <c> element, the object variant above is probably easier to use $ echo '<a><b/><b>bbb</b><c attr="value">ccc</c></a>' | fq -o array=true '.[2][2][1]["#text"]' "ccc"
References
Options
-o array=false
-o attribute_prefix="@"
-o seq=false
yaml
zip
Supports ZIP64.
Timestamp and time zones
References
Options
-o uncompress=true
ENCODINGS, SERIALIZATIONS AND HASHES¶
In addition to binary formats fq also supports various encodings and serialization formats.
At the moment fq does not have any dedicated argument for serialization formats but raw string input -R slurp -s and raw string output -r can make things easier. The combination -Rs will read all inputs into one string (same as jq).
Note that from* functions output jq values and to* functions take jq values as input so in some cases not all information will be properly preserved. For example, the element and attribute order might change and text and comment nodes might move or be merged. yq <https://github.com/mikefarah/yq> might be a better tool if that is needed.
Some example usages:
# read yml (format is probed, use -d yaml to force) and do some query
$ fq '...' file.yml
# convert YAML to JSON
# note the -r for raw string output, without it a JSON string with escaped JSON would be output
$ fq -r 'tojson({indent:2})' file.yml
# add token to URL
$ echo -n "https://host.org" | fq -Rsr 'from_url | .user.username="token" | to_url'
https://token@host.org
# top 3 hosts in src or href attributes:
# -d to decode as html, can't be probed as html5 parsers always produce some parse tree
# [...] to start collecting values into an array
# .. | ."@src"?, ."@href"? | values, recurse and try (?) to get src and href attributes and filter out nulls
# from_url.host | values, parse as url and filter out those without a host
# count to count unique values, returns [[key, count], ...]
# reverse sort by count and pick first 3
# map [key, count] tuples into {key: key, value: count}
# from_entries, convert into object
$ curl -s https://www.discogs.com/ | fq -d html '[.. | ."@src"?, ."@href"? | values | from_url.host | values] | count | sort_by(-.[1])[0:3] | map({key: .[0], value: .[1]}) | from_entries'
{
"blog.discogs.com": 9,
"st.discogs.com": 10,
"www.discogs.com": 14
}
# shows how serialization functions can be used on any string, how to transform values and output some other format
# read and decode zip file and start an interactive REPL
$ fq -i . <(curl -sL https://github.com/stefangabos/world_countries/archive/master.zip)
# select from interesting xml file
zip> .local_files[] | select(.file_name == "world_countries-master/data/countries/en/world.xml").uncompressed | repl
# convert xml into jq value
> .local_files[95].uncompressed string> from_xml | repl
# sort countries by name and select the first one
>> object> .countries.country | sort_by(."@name") | first | repl
# see what current input is
>>> object> .
{
"@alpha2": "af",
"@alpha3": "afg",
"@id": "4",
"@name": "Afghanistan"
}
# remove "@" prefix from keys and convert to YAML and print it
>>> object> with_entries(.key |= .[1:]) | to_yaml | print
alpha2: af
alpha3: afg
id: "4"
name: Afghanistan
# exit all REPLs back to shell
>>> object> ^D
>> object> ^D
> .local_files[95].uncompressed string> ^D
zip> ^D
XML and HTML¶
Similar to from_xml but parses html5 in non-script mode. Will always have a html root with head and body elements. + $opts are:
Assumes object representation if input is an object, and nested arrays if input is an array.
Will automatically add a root doc element if jq value has more than one root element.
If a #seq is found on at least one element all siblings will be sorted by sequence number. Attributes are always sorted. + $opts are:
XML elements can be represented as jq value in two ways, as objects (inspired by mxj <https://github.com/clbanning/mxj> and xml.com’s Converting Between XML and JSON <https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html>) or nested arrays. Both representations are lossy and might lose ordering of elements, text nodes and comments. In object representation from_xml, from_html and to_xml support {seq: true} option to parse/serialize {"#seq": <number>} attributes to preserve element sibling ordering.
The object version is denser and convenient to query, the nested arrays version is probably easier to use when generating XML.
Let’s assume $xml is this XML document as a string:
<doc>
<child attr="1"></child>
<child attr="2">text</child>
<other>text</other> </doc>
With object representation an element is represented as:
> $xml | from_xml
{
"doc": {
"child": [
{
"@attr": "1"
},
{
"#text": "text",
"@attr": "2"
}
],
"other": "text"
}
}
With nested array representation, an array with these values ["<name>", {attributes...}, [children...]].
> $xml | from_xml({array: true})
[
"doc",
null,
[
[
"child",
{
"attr": "1"
},
[]
],
[
"child",
{
"#text": "text",
"attr": "2"
},
[]
],
[
"other",
{
"#text": "text"
},
[]
]
]
]
Parse and include #seq attributes if needed:
> $xml | from_xml({seq:true})
{
"doc": {
"child": [
{
"#seq": 0,
"@attr": "1"
},
{
"#seq": 1,
"#text": "text",
"@attr": "2"
}
],
"other": {
"#seq": 2,
"#text": "text"
}
}
}
Select values in <doc>, remove <child>, add a <new> element, serialize to xml with 2 space indent and print the string
> $xml | from_xml.doc | del(.child) | .new = "abc" | {root: .} | to_xml({indent: 2}) | println
<root>
<new>abc</new>
<other>text</other>
</root>
JSON¶
jq-flavoured JSON¶
Note that fromjson and tojson use different naming conventions as they originate from jq’s standard library.
YAML¶
TOML¶
CSV¶
To work with tab separated values you can use from_csv({comma: "\t"}) or fq -d csv -o 'comma="\t"'.
$opts are:
XML entities¶
URL¶
> "schema://user:pass@host/path?key=value#fragment" | from_url {
"fragment": "fragment",
"host": "host",
"path": "/path",
"query": {
"key": "value"
},
"rawquery": "key=value",
"scheme": "schema",
"user": {
"password": "pass",
"username": "user"
} }
PEM¶
Hex and base64¶
Hash functions¶
Text encodings¶
INTERACTIVE REPL¶
The REPL can be useful in some scenarios:
# start REPL with no (null) input $ fq -i null> # same as $ fq -ni null> # in the REPL you will see a prompt indicating current input and you can type a jq expression to evaluate. # start REPL with one file as input $ fq -i . doc/file.mp3 mp3> # basic arithmetic and jq expressions mp3> 1+1 2 mp3> 1, 2, 3 | . * 2 2 4 6 mp3> [1, 2, 3] | add 6 # "." is the identity function which just returns current input, the mp3 file. mp3> . # access the first frame in the mp3 file mp3> .frames[0] # start a new nested REPL with first frame as input mp3> .frames[0] | repl # prompt shows "path" to current input and that it's an mp3_frame. # Ctrl-D to exit REPL or to shell if last REPL > .frames[0] mp3_frame> ^D # "jq" value of layer in first frame mp3> .frames[0].header.layer | tovalue 3 mp3> .frames[0].header.layer * 2 6 # symbolic value, same as "jq" value mp3> .frames[0].header.layer | tosym 3 # actual underlying decoded value mp3> .frames[0].header.layer | toactual 1 # description of value mp3> .frames[0].header.layer | todescription "MPEG Layer 3" mp3> ^D $ # back to shell
Use Ctrl-D to exit and Ctrl-C to interrupt current evaluation.
EXAMPLES¶
Basic usage¶
fq tries to behave the same way as jq as much as possible, so you can do:
fq . file fq < file cat file | fq fq . < file fq . *.png *.mp3 fq '.frames[0]' *.mp3 fq '.frames[-1] | tobytes' file.mp3 > last_frame
Common usages¶
# recursively display decode tree but truncate long arrays
fq d file
# same as
fq display file
# display all bytes for each value
fq dd file
# same as
fq 'd({array_truncate: 0, string_truncate: 0, display_bytes: 0})' file
# display 200 bytes for each value
fq 'd({display_bytes: 200})' file
# recursively display decode tree without truncating
fq da file
# same as
fq 'd({array_truncate: 0, string_truncate: 0})' file
# display a specific decode tree one level
fq '.path[1].to.value' file
# display a specific decode tree all levels
fq '.path[1].to.value | d' file
fq '.path[1].to.value | dd' file
fq '.path[1].to.value | da' file
# recursively and verbosely display decode tree
fq dv file
# same as
fq 'd({array_truncate: 0, string_truncate: 0, verbose: true})' file
# JSON representation for whole file
fq tovalue file
# or use -V (--value-output) that does tovalue automatically
fq -V . file
# or -Vr if the value is a string and you want a "raw" string
fq -Vr .path.to.string file
# JSON but raw bit fields truncated
fq -o bits_format=truncate tovalue file
# JSON but raw bit fields as md5 hex string
fq -o bits_format=md5 tovalue file
# JSON but raw bit fields as byte arrays
fq -o bits_format=byte_array tovalue file
# look up a path
fq '.some[1].path' file
# look up a path and output JSON
fq -V '.some[1].path' file
# can be a query that outputs multiple values
# this outputs first and last value in .some array and .path, three values in total
fq -V '.some[0,-1], .path' file
# grep whole tree by value
fq 'grep("^prefix")' file
fq 'grep(123)' file
# grep whole tree by condition
fq 'grep_by(. >= 100 and . <= 200)' file
# recursively look for values fulfilling some condition
fq '.. | select(.type=="trak")?' file
fq 'grep_by(.type=="trak")' file
# grep_by(f) is an alias for .. | select(f)?, that is: recurse, select and ignore errors
# recursively look for decode value roots for a format
fq '.. | select(format=="jpeg")' file
# can also use grep_by
fq 'grep_by(format=="jpeg")' file
# recursively look for first decode value root for a format
fq 'first(.. | select(format=="jpeg"))' file
fq 'first(grep_by(format=="jpeg"))' file
# decode file as mp4 and return a result even if there are some errors
fq -d mp4 file.mp4
# decode file as mp4 and also ignore validity assertions
fq -o force=true -d mp4 file.mp4
LINKS¶
github.com/wader/fq <https://github.com/wader/fq>
COPYRIGHT¶
See LICENSE file in source tree.
SEE ALSO¶
AUTHOR¶
Mattias Wadman
| FQ |