OSC 52 で出力をクリップボードにコピーするためのワンライナー
TL;DR
以下のコマンドで ./cmd
の出力をクリップボードにコピーできる。
$ ./cmd | base64 | xargs -I{} echo -n $'\x1b]52;;{}\x1b\\'
OSC 52 とは?
OSC は Operating System Command の略です。
Operating System Command は何かというと、ESC ] ... ESC \
の並びのエスケープシーケンスのことです (ESC
は 0x1b
の 1 byte)。
ESC ]
の直後に数字が続くパターンが多く、特に ESC ] 52
を先頭にしたエスケープシーケンスを OSC 52 といいます。
それで、この OSC 52 が何をしてくれるのかというと、テキストをクリップボードにコピーすることができます。
具体的な書式は以下のようになっています (空白は実際には入力しません)。
ESC ] 52;<Pc>;<Pd> ESC \
c.f. XTerm Control Sequences: Operating System Commands
<Pc>
はクリップボードの種類を表わす文字列です。空だと s0
と同じ意味になるようです。詳しい説明は XTerm Control Sequences のページを参考にしてください。
<Pd>
はクリップボードにコピーしたいデータを base64 エンコーディングした文字列です。
一つ例を試してみましょう。
foo
という文字列をクリップボードにコピーしたいとします。まずは base64 エンコーディングしてみます。
$ echo foo | base64
Zm9v
base64 エンコードした結果 Zm9V
という文字列になることがわかりました。
これを OSC 52 のエスケープシーケンスに埋めこんで実行します。
$ echo -n -e "\e]52;;Zm9v\e\\"
この状態で Ctrl + V
などでペーストしてみると、foo
という文字列が入っているのが確認できると思います。
OSC 52 は何がうれしいの?
コマンドの出力コピーするだけなら pbcopy
とか clip.exe
とか xsel -b
とか使えばいいじゃんと思う方もいらっしゃるかもしれません。
確かにローカルの開発環境で使うだけなら以上のようなコマンドに標準出力を流せば十分です。
しかし、よく困るのが SSH でリモートに接続した際のコピーではないでしょうか?
X11 Forwarding を設定していれば xsel -b
等を用いてコピーしてくることはできるのですが、ローカルに X server を立てておかないといけないとか、リモート側に xsel
コマンドを入れとかないといけないとか、そもそも X11 Forwarding が許可されていない場合があるとか、いろいろと面倒臭い部分も多いのです。
OSC 52 は端末が処理するので、SSH していようと何だろうと端末さえ OSC 52 に対応していれば簡単に使うことができるのが嬉しいポイントです。
唯一注意すべきなのは、端末が対応しているか、また対応しているとして有効化しているかという点になります。筆者が普段使っている Wezterm は特に設定しなくても OSC 52 が有効になっているようです。
tmux 用の設定
SSH 先では tmux
を使う方が多いでしょう。
tmux
は端末上で動いているアプリケーションの出力を一回 tmux
側で吸いとって、場合によってはいろいろと処理をしてから外側の実際の端末エミュレータに渡してくるので、ちょっと注意が必要です。
OSC 52 に関しては基本は以下を .tmux.conf
に設定しておけば良いと思います。
set-option -s set-clipboard on
詳しくは以下などを参考にしてください。
ワンライナーでコピー
さて、本題のワンライナーです (bash, zsh 用です)。
以下のワンライナーで ./cmd
の標準出力をクリップボードにコピーできます。
$ ./cmd | base64 | xargs -I{} echo -n $'\x1b]52;;{}\x1b\\'
まず、OSC 52 のデータ部分は base64 エンコードしたデータじゃないといけないので、最初に base64
コマンドに通します。
次に、標準入力の base64 データをエスケープシーケンスを出力する echo
に埋めこみたいのでプレースホルダー (-I{}
) 付きで xargs
コマンドを使います。
このときちょっと注意が必要なのが、echo
は xargs
から起動されるのでシェル組み込みではなく外部コマンドの /bin/echo
等が呼ばれるという点です。すると、\e
-> ESC
等を解釈してくれる-e
オプションが使えなかったりすることがあります [1]。
そこで、$'...'
という bash/zsh の特殊なクオートを使っています [2]。この $'...'
の中では \xHH
の形式の 16進記法を対応する 1 byte に展開してくれるので今回のテクニックが成立します。
便利なシェル関数・シェルスクリプトもあるよ
正直なところ、何回も使うのであればたぶん以下のようなシェル関数やシェルスクリプトを使ったほうが良いです。
関数定義するのもめんどいし、シェルスクリプト持ってくんのもめんどくさいし、とにかく今 1 回だけコピーしてきたいんじゃ!ってときにサッとワンライナーで書けたら役に立つ...かもしれません。
以上
-
筆者の使っている Mac 環境だと使えませんでした。Linux 環境なら GNU Coreutils 版が入っていることが多いと思うのでたぶん
-e
オプションも使えることが多いと思います ↩︎
Discussion