cmd2ftp

はじめに

cmd2ftp は、ローカルホスト上で実行するコマンドの出力を、ftp を経由して、直接リモートホスト上のファイルに出力するための ftp クライアントのラッパーである。

ローカルホスト上で、シェルで処理した出力を、リモートホストに書き出したい、という時に、普通だったら、 ssh とパイプを使うところだが、ssh は ftp に較べると、問題外に性能が悪く、ここは ftp を使いたい所だ。

ところが、昔ながらの ftp クライアントは、この機能、すなわちローカルコマンド出力を直接 put する機能があるが、対話的に操作をする気になれないようなインタフェースになっている。 そこで、この操作性を改善し、ssh の手軽さで、ftp の性能を享受すべくこのラッパを書いた。

※ 後日談だが、公開後に、cmdwftp の機能は ncftp に同梱されている ncftpput で可能である、という指摘を頂戴した。この議論に関しては、凡例を参照されたい。

更新情報
動作に必要な環境
インストール
凡例
例題1 簡単な例を ssh, ftp ,cmd2ftp で解いて比較する
例題2 より複雑な例
教訓・その他
Pod::Usage モジュール
Known Bug
非アスキー文字の文字化け可能性について
連絡先
リンク
関連するソフトウエア

更新情報

20070118 Ver0.04

動作に必要な環境

インストール

ここ にあるtarballを開梱して、環境に合せて Makefile を修正してから以下の操作を行なう。
% tar xvjf cmd2ftp-0.01.tar.bz2
% cd cmd2ftp-0.XXX
% make install

正しくインストールされると man cmd2ftp もしくは cmd2ftp -man でマニュアルが表示される。

凡例

例題1 簡単な例を ssh, ftp ,cmd2ftp で解いて比較する

ローカルホストで 'cat DersuUzala_1974.md{f,0,1,2}' とした結果を リモートホスト video の /tmp に image.iso という名前で出力する。

ssh を使った解

↓のように自然に美しく書くことができる。
% cat DersuUzala_1974.md{f,0,1,2} | ssh video "cat > /tmp/image.iso"
しかし ssh のファイル転送は重い。無駄だと思うだろう。こんなもので満足していては駄目だ。

ftp を使った解

オリジナルの ftp は、ローカルホストのコマンド出力を、中間ファイルを作らずに、リモートホストへ直接 put できる。 そして驚くべきことに、現代的で人気のある lftp とか ncftp2 では、こういう芸当は出来ない。 しかもだ、この機能は、man の put の項には書いていなくって、一番後ろにある FILE NAMING CONVENTIONS という、一見しただけでは関係が読めないよう項目にこっそりと書いてある。 俺も、この cmd2ftp を書くまでは、こんなこと知らなかった。

これを使うと、↓のようになる。

% ftp -i -n video << END
heredoc> user Id Pass
heredoc> cd /tmp
heredoc> put |"cat DersuUzala_1974.md{f,0,1,2}" "image.iso"
heredoc> quit
heredoc> END
スクリプト中に書くのならいざ知らず、今時対話的にこんな操作をする人間なんていないだろう。やってられないよな。

しかし、だ、ファイル転送性能は、ssh に較べて ftp の方が圧倒的に高いんだ。これは適当なラッパをデッチ上げるしかない。

cmd2ftp を使った解

独自構文になってしまうが、単純な転送なら性能は数倍になるので、まあこれなら対話的にも使う気になる許容範囲だろう。
% cmd2ftp -h video -u Id,Pass -c "'cat DersuUzala_1974.md{f,0,1,2}' -d /tmp -o image.iso

ncftpput を使った解

以下は、高橋 "masaka" 正和 さんのコメントに依る。

ncftp に同梱されている ncftpput (-c オプション) を使うと、出力をパイプを通してリモートホストに put できる。

$ cat DersuUzala_1974.md{f,0,1,2} | ncftpput -u Id -p Pass -c video /tmp/image.iso
信頼出来る経路を使う分にはベストプラクティスだと思う。こいつの存在を知っていたら cmd2ftp を書くことはなかっただろう。

とか思ったんですが、ちょっと試した範囲では、ftp でやるのにくらべて低速でした。という訳で cmd2ftp を書いてやっぱりよかった。

nc(netcat) を使った解

本項は 尾山@渋谷さんのコメントによる。

netcat をバッチ的に使う場合はコツがいる

% ssh video 'nc -l -p 2000  > /tmp/image.iso ' & ; \
     sleep 1 ; cat DersuUzala_1974.md{f,0,1,2} | nc -q 0 video 2000

更にこいつは、ssh 同様に、リモート側で出力をパイプに繋げて更に処理をすることができる。 下は、リモート側でパイプラインを繋げた例

% ssh video 'nc -l -p 2000 | wc -l > /tmp/foo.txt ' & ; \
     sleep 1 ; cat test.txt | nc -q 0 video 2000
これだと、ftp のように、平文でパスワードが流れたりしないし、ssh より軽い。 しかし、環境によって sleep とか nc -q に与える待ち時間を調整する必要がある。 使い手を選ぶ道具であると思う。

例題2 より複雑な例

ftp の put のファイル名として与えるシェルコマンドの制限について

改行を含まない限り、Bourne Shell が解釈できるコマンド列は、期待通りに動作する。

シェル変数も、制御構造も、パイプやリダイレクトも使うことができるし セミコロンで複数コマンドを列挙することもできる。

途中に改行があると、そこでコマンドはシェルに渡されてしまって、次に出現する空白文字で区切られたトークンが、出力ファイル名になる。

cmd2ftp でのコマンド制限

cmd2ftp では、コマンド中の改行を許容する。つまり次のように、書くこともできる。

% cmd2ftp -h video -u Id,Pass --cmd 'for f in *
quote> do ls -l $f
quote> done ' -d /tmp -o result.txt

教訓・その他

Pod::Usage モジュール

Getopt::Long と Pod::Usage モジュールを併用し、ヘルプオプション(?help/-?) の出力を Pod から生成するようにした。

svn のリリースタグを make で、プログラムのバージョン文字列に埋め込む

こちら に書いた。

Known Bug

非アスキー文字の文字化け可能性について

?cmd/-cオプションで与えるコマンド文字列中に非アスキー文字があるとき、これが文字化けする可能性があります。

連絡先

動作/不動作報告、問題報告、変更提案、御要望などは、他のユーザの方とも情報共有できるように、なるべく、こちら へのコメントとして、お願い致します。

リンク

関連するソフトウエア


連絡先:webadmin.itsumi@gmail.com このページは muse.el で作成しています。 Emacs