echoコマンドの使い方について語る2

こんにちは。株式会社フィックスポイントのよしだです。

今回は、 echo コマンドの応用編として、エンジニアの tennashiさんより、クリップボードへの書き込み・読み込みについて発表がありました。

前回に比べて、少し踏み込んだ内容になっていますので、 echo コマンドを活用したい方は、是非読んでみてください。(前回の記事はこちら

クリップボードにコピーする

実行するコマンドは以下の通りです。

$ echo -e "\e]52;c;ZnVnYWZ1Z2E=\a"

ここでは、単一のスケープシーケンスを実行しているため、 echo コマンド自体の実行結果は空(行)になっています。*1

今回も、前回同様にコマンドを分割して考えてみましょう。

すると、以下のように分けることが可能です。

    • \e]*\a: カテゴリ指定
    • 52: コマンドの種類
    • c: パラメータその1
    • ZnVnYWZ1Z2E=: パラメータその2

それぞれの要素を見ていきましょう。

カテゴリ指定

カテゴリ指定については、少しだけ文字が変わっていることに注目してください。

文字色の変更のときは \e[ から始まっていましたが、今回は \e] から始まっています。

\e] から始まるエスケープシーケンスは、 OS に関連した操作が定義されています。

その中に、今回利用しているクリップボード連携機能もあります。*2

 

終端文字も変更されており、今回は m ではなく \a に変わっています。

 \a は、本来であればベル文字と呼ばれており、(そのように設定している PC では)単体で使えば PC からビープ音が鳴るようになっています。

ただ今回は、一連のシーケンス終端文字として解釈されるので、実行の度にビープ音が鳴ったりはしません。*3

コマンドの種類

この項目については、特に変わったことはありません。

52クリップボード連携コマンドを意味しています。

パラメータの種類

先にパラメータその2の ZnVnYWZ1Z2E= に着目しましょう。

お分かりの方もいるかと思いますが、Base64 エンコードされた fugafuga です。

 echo コマンドでは、次のように生成が可能です。

$ echo -en "fugafuga" | base64
ZnVnYWZ1Z2E=
Base64とは?
Base64 は、任意の文字列を a-zA-Z0-9+/ の64 文字で表現するための仕様です。

例えば、 HTTP 1.1 では送受信されるデータはテキストデータと定められています。
そのため、HTTP の範囲内で画像(バイナリデータ)等を送受信する際は、何らかの方法でテキストデータ(つまり "目" で認識できる文字列) に変換する必要があります。

Base64 は、このような場合に有用です。

ちなみに、= はデータ長を調整するためのパディングにのみ使われます。

そのことから、先の文字列を見て Base64 エンコードされていることが、分かる人には分かるという訳です。(もちろんそうでない場合も多々あります)

今回のエスケープシーケンスでは、クリップボードに挿入したい文字列を Base64 に変換したものをパラメータに指定することになっています。

そのため、 ZnVnYWZ1Z2E= を指定しているのです。

 

次に、先程飛ばしたパラメータ1の c について説明します。

これは、いわゆる Ctrl+C Ctrl+V で操作できるクリップボードを使うことを意味しています。

コマンドの種類を 52 とした時点で、クリップボード連携というのは分かっているのに、さらにクリップボードを指定するとは…?と思われた方もいるかもしれません。

実は、Linux における標準的なデスクトップ環境 X11 では、クリップボードと言ったときには複数のバッファが存在しています。
それらは CLIPBOARD PRIMARY SECONDARY と呼ばれており、どれを利用するのかは明示しなければなりません。

CLIPBOARD バッファがいわゆるクリップボードとなっており、それを利用するという指定が c となっているのです。

まとめ

以上の内容から、最初に示したエスケープシーケンスの意味はご理解いただけたのではないでしょうか。

クリップボードの読み込み

冒頭でもお伝えした通り、クリップボードへは書き込みだけでなく読み込みも可能です。

入力するエスケープシーケンスは以下の通りです。

$ echo -e "\e]52;c;?\a"

これを実行すると、現在 CLIPBOARD に入っている文字列が ? の部分に補完された状態で表示されます。
先程の書き込みの際と同じく、 Base64 エンコードされた状態のものにはなりますが、読み込みが可能という訳です。

クリップボード読み込みの危険性

クリップボードの読み込み手順をご紹介はしましたが、この機能はある意味で危険です。

クリップボードには、比較的センシティブな情報が入っていることもあるため、それが手軽に取得できるのは危険だと言えます。
例えば、 curl | sh によるインストール手順に、クリップボードの内容を取得して外部に投げるという操作が書かれており、情報漏洩に繋がる可能性もあるのです。

そのような危険性があるため、クリップボードの読み込み機能をデフォルトで無効にしているターミナルエミュレータや、そもそも実装していないものも存在しています。
具体的には、iTerm2 は前者で、gnome-terminal(VTE 系) は後者です。
ちなみに、今回の勉強会担当者が利用している Alacritty はデフォ有効でした。

おまけ: tmux とクリップボード

今までの話題に関連して、tmuxとクリップボードの関係について記載しておきます。

tmux.conf を開くと、以下のように記述してあるのではないでしょうか。

bind-key -T copy-mode-vi C-j send -X copy-pipe-and-cancel 'xsel -i'
bind-key -T copy-mode-vi Enter send -X copy-pipe-and-cancel 'xsel -i'
bind-key -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel 'xsel -i'

これは、 tmux でクリップボード連携をするための設定としてよく紹介されているものです。
まず、この設定値が機能していない可能性があることを念頭に置いてください。

tmux には set-clipboard オプションが存在し、前項までで説明したエスケープシーケンスによるクリップボード連携機能の有効無効を設定できるようになっています。
ちなみに、tmux 2.6 以降ではデフォルトで有効化されています。

先に記述した bind-key による設定はエスケープシーケンスではなく、 xsel コマンドを利用した別のクリップボード連携方法です。
このことから、両設定が実のところコンフリクトしている可能性があるのです。

そのため、bind-key による設定を正しく使いたければ、 set-clipboard オプションを off にしておくとよいです。

さらに、 tmux 3.2 からは copy-command というオプションが追加されており、上記 bind-key による設定を消し、以下のコマンドを入力することで同じ挙動にできます。

set-option -s copy-command 'xsel -i`

set-clipboard のデフォルト値で動くならそれでよいと思われるかもしれません。

しかし、エスケープシーケンスによるクリップボード連携には、文字数制限という大きなデメリットがあります。
また Linux 以外ではきちんと試していませんが、端末エミュレータ自体の機能なので設定値が OS に依存しないはずです。
以上のことから、どちらを利用するか用途に応じて考えていただければと思います。

参加者の反応

今回の発表を聞いた参加者の反応です。

かなり深い知識の話にも、みなさん興味津々です👀

f:id:aqui_jasmine:20211216103107p:plain

最後に

今回は、echoコマンドでのクリップボードの書き込み・読み込みについてご紹介しました。

注意するべき点もありますので、そこも頭に置きながら活用していただければ幸いです。

 

 

株式会社フィックスポイントでは、一緒に働いてくれるメンバーを募集しています!

詳細は、こちらをご覧ください。

*1:`echo`コマンドはデフォルトで出力した結果に改行を付けるため、この挙動が嫌であれば `-n`オプションを追加するとよいです。

*2:`\e]`の下にあるシーケンスは Operation System Command と呼ばれています。今回利用したシーケンスは OSC52 という呼称です。

*3:Xterm の場合は終端文字列は、`\e\\` (これは `ST` String Terminator と呼ばれている) も利用できる