LoginSignup
14
12

More than 5 years have passed since last update.

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

Last updated at Posted at 2015-09-11

導入

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


$ write user01
(line 1......)
(line 2......)
...
#入力し終わったらCtrl+Dを押す

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

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

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

方法

以下受信側のユーザ名はuser01、送信側はuser00とします。

メッセージ(標準入力)編

送信側は次のコマンドを入力します。

$ xz - | base64 | write user01

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

$ base64 -d | unxz -

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

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

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

だけでも構いません。

ファイル編

送信側は次のように入力します。filepath/filenameは送信したいファイルへのパス・名前です。

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

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

$ base64 -d | unxz - > filename

実際の例

メッセージを送信してみる

送信側
bash-4.1$ xz - | base64 | write user01
メッセージ送信のテスト
このメッセージはテストメッセージです。
このように日本語も送れます。
ちゃんと届いているかな?
#include <stdio.h>

int main(int argc, char *argv[]) {
  puts("Hello, World!!!");
  return 0; //C言語のテスト
}
(最後にCtrl+Dを押す)
受信メッセージ
メッセージ 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
受信側コマンド
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言語のテスト
}

ファイルを送信してみる

送信側
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
受信メッセージ
メッセージ 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
受信側コマンド
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)

14
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
12