OSC 52 (Operating System Command 52) is an ANSI escape sequence that allows a terminal application to read or write to your local system's clipboard.
Note
Not all terminal emulators support OSC 52, and those that do usually restrict it to writing to the clipboard, disallowing reading from it.
Restricting it to writing is to prevent the scenario of a malicious application reading sensitive information from the user's clipboard.
More about terminal support below.
printf "\e]52;c;%s\a" "$(printf '%s' 'Hello, World!' | base64 -w 0)" # GNU
printf "\e]52;c;%s\a" "$(printf '%s' 'Hello, World!' | base64 -b 0)" # macOS/BSDThe text Hello, World! should now be on your clipboard, assuming your terminal supports the OSC 52 escape sequence.
Explanation:
\e]52begins an escape sequence for the OSC 52 command- The
\e]part means we are starting an Operating System Command (OSC) \eis ESC . Equivalents:\033(octal) and\x1b(hex)- 52 is the specific command number used for clipboard operations
- The
cspecifies standard clipboard for the clipboard specifier argument (details).\ais BEL. Equivalents:\007(octal) and\x07(hex)- Use of BEL for string terminator is non-standard but widely supported
- For strict standard adherence, use
\e\\for the string terminator - See https://unix.stackexchange.com/q/729360
- The
-w 0option tobase64disables base64's default behavior of line wrapping. You could also usebase64 | tr -d '\n'. On macOS/BSD, use-b 0instead of-w 0.
Terminals that support OSC 52 for writing to the clipboard include:
- Ghostty
- iTerm2
- WezTerm
- Alacritty
- Kitty
- Windows Terminal
Note
Gnome Terminal, Ptyxis, and other VTE-based terminals do not support OSC52 yet. Watch this issue:
- Add support for OSC 52 (#2495) · Issue · GNOME/vte
https://gitlab.gnome.org/GNOME/vte/-/issues/2495
Work-around: tmux can support OSC52, even in Gnome Terminal.
I put this shell script at ~/.local/bin/osc52 and made it executable with chmod +x.
#!/usr/bin/env bash
# Open the OSC 52 escape sequence and specify the system clipboard (c)
printf '\e]52;c;'
# Read file args, or from stdin if no args, and encode with base64
# Options used:
# -w 0 disables line wrapping (On BSD/macOS use -b instead of -w)
base64 -w 0 "${@}"
# Close the escape sequence
# Two escape sequences work:
# \e\\ Standard string terminator
# \a BEL also works. This is non-standard but widely supported
# https://unix.stackexchange.com/q/729360
printf '\a'If you prefer a binary executable over a shell script, you can use this go program:
https://github.com/theimpostor/osc
Install:
go install -v github.com/theimpostor/osc@latest
Usage:
echo Hello | osc copy
For vim, I use this plugin:
- ojroques/vim-oscyank: A Vim plugin to copy text through SSH with OSC52
https://github.com/ojroques/vim-oscyank
Then I visually select a block of text and press <leader> followed by c to copy it to the clipboard.
(I use Vim’s default leader of backslash, so I press \ followed by c.)
" OSC52 clipboard support for vim 7.4
" ========================================
"
" This function and visual keybinding will send the yanked text to the system clipboard, if
" your terminal supports the OSC 52 escape sequence.
"
" I first tried the ojroques/vim-oscyank plugin, but it wasn't
" compatible with vim 7.4. This function and keybinding is a workaround.
"
" Function to send yanked text to OSC52 sequence
function! OSC52()
let yanked = @"
"call system("base64 -w 0 | xargs -0 printf '\\e]52;c;%s\\a' >/dev/tty", yanked)
call system("{ printf '\\e]52;c;'; base64 -w 0; printf '\\a'; } >/dev/tty", yanked)
if v:shell_error == 0
echo 'Copied to clipboard via OSC52'
else
echoerr 'OSC52 clipboard copy failed'
endif
endfunction
" Map visual yank to the OSC52 function as a side effect
" Maybe I should add more yank mappings, but I decided to keep it simple
" Remember, this is merely a workaround for vim-oscyank not being compatible
" with vim 7.4. It won't be needed for long.
vnoremap <silent> y y:call OSC52()<CR>" Alternate implementation:
" Function to copy the visually selected range to the clipboard
" Limitation: linewise only
function! WriteVisualSelectionToClipboard() range
"silent '<,'>w !base64 -w 0 | xargs -0 printf '\e]52;c;\%s\a' >/dev/tty
silent '<,'>w !{ printf '\e]52;c;'; base64 -w 0; printf '\a'; } >/dev/tty
endfunction
" Map it to <leader>c in visual mode
" (Same default key binding as vim-oscyank)
" vnoremap is non-recursive and safe
vnoremap <leader>c :call WriteVisualSelectionToClipboard()<CR>