OSC 4 query — Read 256-color palette index (`\x1b]4;<n>;?\x07`)
Ask the terminal what RGB value is currently bound to palette index `n` (0–255) — used by theme inspectors, screenshot tools, and palette-migration scripts.
Byte forms
Every common string-literal form so you can paste-and-search either direction.
\x1b]4;<n>;?\x07\033]4;<n>;?\007\e]4;<n>;?\aESC ] 4 ; n ; ? BEL1b 5d 34 3b ... 3b 3f 07Description
The *query* counterpart to OSC 4 (see `osc-set-palette` for the set side). Send `\x1b]4;<n>;?\x07` where `<n>` is the palette index 0–255 and the terminal replies on stdin with `\x1b]4;<n>;rgb:RRRR/GGGG/BBBB\x07` — same XParseColor-shaped, 16-bit-per-channel form used by the OSC 10 / 11 / 12 query (see `osc-color-query`). Multiple indices can be batched in one request — `\x1b]4;0;?;1;?;2;?\x07` returns three replies back-to-back. **Use cases**: - **Theme inspectors / dotfile generators** — dump the live 16 ANSI colors plus the 6×6×6 cube to YAML / JSON so a screenshot-faithful clone can be reproduced on a fresh machine. - **Screenshot / asciinema-style recorders** — capture the running palette so playback under a different theme still reproduces the original visuals. - **Palette migration scripts** — read out the current colors before applying a new theme, so the old one can be restored verbatim (a defensive `osc-reset-palette` only restores the *built-in* defaults, not whatever the user customised). - **CI test runners** — assert that a custom OSC 4 set actually took effect, by querying back the index immediately afterwards. **Reply parsing** — the index in the reply matches the index in the request, so when batching multiple `;<n>;?` pairs you must demultiplex by `<n>` (replies are not guaranteed to arrive in send order on every terminal, though most do). Time-out the read at ~100 ms per index and treat missing replies as 'index not customised — defer to ANSI/256 defaults'. **Caveats** — Linux console / Windows cmd ignore the query and reply nothing (timeout-and-fall-back is the correct strategy). macOS Terminal replies only for indices 0–15. Modern emulators (xterm / iTerm2 / Kitty / Alacritty / WezTerm / Ghostty / Konsole) all reply for the full 0–255 range.
Spec citation: xterm-ctlseqs (OSC 4 query)
Parameters
| n | Palette index 0–255 (0–7 = basic ANSI, 8–15 = bright ANSI, 16–231 = 6×6×6 cube, 232–255 = grayscale ramp). |
| ? | Query sentinel — replaces the spec to request the current binding instead of changing it. |
Examples
# Read palette index 1 (red) and print it.\nold=$(stty -g); stty -echo raw min 0 time 1\nprintf '\033]4;1;?\007' > /dev/tty\nIFS= read -r -d $'\\a' reply < /dev/tty\nstty "$old"\necho "palette[1] = ${reply##*rgb:}"# Dump first 16 ANSI colors as a Python dict.\nimport sys, termios, tty, select, re\nfd = sys.stdin.fileno(); old = termios.tcgetattr(fd); tty.setraw(fd)\ntry:\n palette = {}\n for i in range(16):\n sys.stdout.write(f'\x1b]4;{i};?\x07'); sys.stdout.flush()\n if select.select([fd], [], [], 0.1)[0]:\n buf = b''\n while not buf.endswith(b'\\x07'):\n buf += sys.stdin.buffer.read1(64)\n m = re.search(rb'rgb:([0-9a-f]+)/([0-9a-f]+)/([0-9a-f]+)', buf, re.I)\n palette[i] = '#' + ''.join(g.decode()[:2] for g in m.groups())\n print(palette)\nfinally:\n termios.tcsetattr(fd, termios.TCSADRAIN, old)// Query a single palette index. (raw stdin setup elided — see osc-color-query)\nfor _, idx := range []int{0, 1, 2, 3, 4, 5, 6, 7} {\n fmt.Printf(\"\\x1b]4;%d;?\\x07\", idx)\n // read reply with bufio.Reader.ReadString(0x07), parse rgb:RRRR/GGGG/BBBB\n}// Batch query indices 0..15 in one write.\nprocess.stdin.setRawMode(true); process.stdin.resume();\nconst req = Array.from({length: 16}, (_, i) => `4;${i};?`).join(';');\nprocess.stdout.write(`\\x1b]${req}\\x07`);\nlet buf = '';\nprocess.stdin.on('data', chunk => {\n buf += chunk.toString();\n const matches = [...buf.matchAll(/\\]4;(\\d+);rgb:([0-9a-f]+)\\/([0-9a-f]+)\\/([0-9a-f]+)\\x07/gi)];\n if (matches.length === 16) {\n process.stdin.setRawMode(false); process.stdin.pause();\n console.log(matches.map(m => [+m[1], `#${m[2].slice(0,2)}${m[3].slice(0,2)}${m[4].slice(0,2)}`]));\n }\n});/* Query a single palette index — read until BEL. */\nprintf(\"\\x1b]4;%d;?\\x07\", index); fflush(stdout);\nchar buf[128]; int n = read(0, buf, sizeof buf - 1);\nif (n > 0) { buf[n] = 0; /* parse rgb:RRRR/GGGG/BBBB out of buf */ }Terminal support
- xterm
- yes
- Linux console (fbcon)
- no
- macOS Terminal.app
- partial
- iTerm2
- yes
- Windows Terminal
- yes
- cmd.exe / ConPTY
- no
- kitty
- yes
- alacritty
- yes
- WezTerm
- yes
- Ghostty
- yes
- GNOME Terminal
- partial
- Konsole
- yes
- tmux
- no
- GNU screen
- no
| xterm | Linux console (fbcon) | macOS Terminal.app | iTerm2 | Windows Terminal | cmd.exe / ConPTY | kitty | alacritty | WezTerm | Ghostty | GNOME Terminal | Konsole | tmux | GNU screen |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| yes | no | partial | yes | yes | no | yes | yes | yes | yes | partial | yes | no | no |