同一のLinuxサーバにログインしているユーザ同士で日本語を含むメッセージ・ファイルをやり取りする

#導入
LinuxサーバにSSHなどでログインしている時、場合によっては同じサーバにログインしている他のユーザにメッセージを送りたくなることがあるかもしれません。その場合、メッセージにASCII文字しか含まないことがわかっているならば`write`コマンドを使用して、

```bash

$ write user01
(line 1......)
(line 2......)
...
#入力し終わったらCtrl+Dを押す
```
と入力すれば、他のユーザ(この場合は`user01`)メッセージを送信することができます。しかし、このコマンドで日本語などを含んだメッセージ・ファイルを送信しようとすると日本語などがエスケープされてしまい、送信しても受信側からは英数字など以外は意味不明な文字列になってしまいます。

しかし、少し工夫すれば`write`コマンドでなんとかメッセージを送信できます。

紹介する方法はCentOS/RHEL 6.7で確認しています。Linux以外のUnixでもできる可能性がありますが、保障はしていません。

#方法
以下受信側のユーザ名は`user01`、送信側は`user00`とします。
##メッセージ(標準入力)編
送信側は次のコマンドを入力します。

```bash
$ xz - | base64 | write user01
```

入力したらメッセージを入力し、Ctrl+Dを押します。受信側は、

```bash
$ base64 -d | unxz -
```
と入力し、EOFの直前までの英数字記号の羅列をコピーして貼り付け、Ctrl+Dを入力します。

メッセージがそこまで長くない場合はxz・unxzを噛ませる程でもないですので、

```bash
#送信側
$ base64 | write user01
#受信側
$ base64 -d
```

だけでも構いません。
##ファイル編 
送信側は次のように入力します。`filepath/filename`は送信したいファイルへのパス・名前です。

```bash
$ xz -c filepath/filename | base64 | write user01
```

受信側では次のように入力し、受信した英数字記号文を入力し、Ctrl+Dを押します。filenameは保存名です。

```bash
$ base64 -d | unxz - > filename
```
#実際の例
## メッセージを送信してみる
```text:送信側
bash-4.1$ xz - | base64 | write user01
メッセージ送信のテスト
このメッセージはテストメッセージです。
このように日本語も送れます。
ちゃんと届いているかな？
#include <stdio.h>

int main(int argc, char *argv[]) {
  puts("Hello, World!!!");
  return 0; //C言語のテスト
}
(最後にCtrl+Dを押す)
```

```text:受信メッセージ
メッセージ from user00@ssh.xxx.yyy.zz.jp on pts/0 at HH:MM ...
/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AEhANFdAHGg0DAEg8QS7SG4KTiUXcsCxBjQBXJ1nSwF
efkfCwdMzZ4mbZTe0lHLS62UUotlBA+pw8XTv+Mbhj65o99EPTTFwpaMrDZTdeutqQK2wp7QarfA
sb7w7y5nJbv5wbGrj4IIyUqUgjK9bdv+BtdxDHbI3AIcEDxUKU4MJfJpJFnHPtHr9QDaFoUOTjxK
2hoRgeUrsxQ3S4mer8gEJuzFrOi0+lPm7n6NJnwK5Rqqx3gzThJ/0yL5vPh+cau/q0qfkxaAlF5V
vcbOSAHpWU4pfVUAAAAAAN4pD3j0opmtAAHtAaICAADR8AmwscRn+wIAAAAABFla
EOF
```
```text:受信側コマンド
bash-4.1$ base64 -d | unxz -
(貼り付け)
/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AEhANFdAHGg0DAEg8QS7SG4KTiUXcsCxBjQBXJ1nSwF
efkfCwdMzZ4mbZTe0lHLS62UUotlBA+pw8XTv+Mbhj65o99EPTTFwpaMrDZTdeutqQK2wp7QarfA
sb7w7y5nJbv5wbGrj4IIyUqUgjK9bdv+BtdxDHbI3AIcEDxUKU4MJfJpJFnHPtHr9QDaFoUOTjxK
2hoRgeUrsxQ3S4mer8gEJuzFrOi0+lPm7n6NJnwK5Rqqx3gzThJ/0yL5vPh+cau/q0qfkxaAlF5V
vcbOSAHpWU4pfVUAAAAAAN4pD3j0opmtAAHtAaICAADR8AmwscRn+wIAAAAABFla
(Ctrl+Dを2回押すか改行してCtrl+D)
メッセージ送信のテスト
このメッセージはテストメッセージです。
このように日本語も送れます。
ちゃんと届いているかな？
#include <stdio.h>

int main(int argc, char *argv[]) {
  puts("Hello, World!!!");
  return 0; //C言語のテスト
}
```
## ファイルを送信してみる
```text:送信側
bash-4.1$ cat test.cpp
#include <iostream>

const unsigned long max = 1UL << 16;
const unsigned long shift = 52;
const unsigned long offset = 1UL << SHIFT;

int main() {
  unsigned long ans = 0UL;
  for(unsigned long i = 1UL; i <= max; i++) {
    ans += offset / (i * i);
  }
  double ans2 = (double)ans / (double)offset;
  std::cout << "π^2/6≒" << ans2 << std::endl;
  return 0;
}
bash-4.1$ xz -c test.cpp | base64 | write user01
```

```text:受信メッセージ
メッセージ from user00@ssh.xxx.yyy.zz.jp on pts/0 at HH:MM ...
/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AFpAN1dABGaScZHDxOiAHc7HOuLZBMXIc2axTFQUSTy
M6hQTuQCj2G1gv27TtslK1oMdIKTBoeHldYP6I0nPed/oF3PoNbxeCKWz96Zl4ZPLlrMnGXeuYuy
hWhUx+0GMVjNna2u3wkAQ135ILxWwuLknKpw4/N9CvEHf+18pBXQJWNR8t46kBLe95rq+oM0TudD
wyq3NfObI/3Mknq1YPPjhO4WS20XNoChLxuRV1DCFcOBZ2g7ykZMHfDzlPwTYg/KoxfNN8Ew76Ic
5sTKdSXBIiG/9bAG34HGFgBNd9IbN+kgAAAAAJQBizzyUzGRAAH5AeoCAACOwO52scRn+wIAAAAA
BFla
EOF
```
```text:受信側コマンド
bash-4.1$ base64 -d | unxz - > test.cpp
(貼り付け)
/Td6WFoAAATm1rRGAgAhARYAAAB0L+Wj4AFpAN1dABGaScZHDxOiAHc7HOuLZBMXIc2axTFQUSTy
M6hQTuQCj2G1gv27TtslK1oMdIKTBoeHldYP6I0nPed/oF3PoNbxeCKWz96Zl4ZPLlrMnGXeuYuy
hWhUx+0GMVjNna2u3wkAQ135ILxWwuLknKpw4/N9CvEHf+18pBXQJWNR8t46kBLe95rq+oM0TudD
wyq3NfObI/3Mknq1YPPjhO4WS20XNoChLxuRV1DCFcOBZ2g7ykZMHfDzlPwTYg/KoxfNN8Ew76Ic
5sTKdSXBIiG/9bAG34HGFgBNd9IbN+kgAAAAAJQBizzyUzGRAAH5AeoCAACOwO52scRn+wIAAAAA
BFla
(Ctrl+Dを2回押すか改行してCtrl+D)
bash-4.1$ cat test.cpp
#include <iostream>

const unsigned long max = 1UL << 16;
const unsigned long shift = 52;
const unsigned long offset = 1UL << SHIFT;

int main() {
  unsigned long ans = 0UL;
  for(unsigned long i = 1UL; i <= max; i++) {
    ans += offset / (i * i);
  }
  double ans2 = (double)ans / (double)offset;
  std::cout << "π^2/6≒" << ans2 << std::endl;
  return 0;
}
```
ちゃんと「π」「≒」の2文字が正しく表示されています。
#仕組み
`write`コマンドでは英数字・記号しか正しく送れません。なので、それ以外の文字が含まれているならば無理やり英数字・記号に変換してやらなければなりません。その手法にはいくつかありますが、最も代表的なものにBase64と呼ばれるものがあります。これを利用すると日本語などASCII範囲外の文字や制御文字などを含むデータを大小アルファベット・数字・「+」「/」の64文字と「=」で表すことができます。しかし、このままでは文字列の長さが元の4/3に膨れ上がってしまいます。

それを抑えるため、Base64で符号化する前に「xz」という圧縮フォーマットで圧縮をかけます。これはLinuxで最も一般的であろう「gzip」(gz)よりも圧縮率が高いです。しかし、送る文字列が短い場合は符号化しない方が文字列の長さが短い場合があります。その場合はxzを通さずにいきなりBase64で符号化します。(送信側の場合は`base64 | write user01`)