FTP でも rsync みたいにコマンドからファイル転送したい

この記事は書かれてから1年以上が経過しており、最新の情報とは異なる可能性があります

ターミナルで何でも行う人にとって、FTP の GUI クライアントはもう辛すぎるのです。 コマンド1つで rsync のようにアップロードしたいのです。

同じように考える人は多いらしく、 “rsync”, “FTP” でググると “rsync over FTP” がどうのこうのと書かれた記事は散見するものの、 そんなものないけど、代わりに lftp 使うといいよ。みたいな記事が多くあります。

なので、(過去に1度使った記憶あるものの、改めて)試しに使ってみました。

なお、MacBook Pro の El Capitan です。Homebrew でインストールします。

brew install lftp
man lftp

lftp コマンドは、基本的に ftp コマンドと同じく対話形式のコマンドなのですが、 オプションで -e や -c とともに対話形式の内容のコマンド(サブコマンド?)をつけてやると そのまま実行できます。

また、対話形式をテキストファイルにまとめておき、 -f オプションで利用することも可能です。 以下は lftp コマンド自体のシンタックスとオプションです。(man lftp より抜粋)

SYNTAX
       lftp [-d] [-e cmd] [-p port] [-u user[,pass]] [site]
       lftp -f script_file
       lftp -c commands
       lftp --version
       lftp --help

OPTIONS
       -d     Switch on debugging mode.

       -e commands
              Execute given commands and don't exit.

       -p port
              Use the given port to connect.

       -u user[,pass]
              Use the given username and  password  to  connect.  Remember  to
              quote  the  password properly in the shell. Also note that it is
              not secure to specify the password on command line, use ~/.netrc
              file   or   LFTP_PASSWORD  environment  variable  together  with
              --env-password option. Alternatively you can use ssh-based  pro-
              tocols  with authorized keys, so you don't have to enter a pass-
              word.


       --norc Don't execute rc files from the home directory.

       -f script_file
              Execute commands in the file and exit.  This option must be used
              alone without other arguments (except --norc).

       -c commands
              Execute  the  given commands and exit. Commands can be separated
              with a semicolon, `&&' or `||'. Remember to quote  the  commands
              argument  properly in the shell.  This option must be used alone
              without other arguments (except --norc).

上記から、接続情報は lftp のオプションとして渡しつつ、 それとは別に対話形式内のコマンドにて実際のファイルアップロードを行います。

今回はその中の mirror コマンドを利用し、 rsync に近いことを行ったのを シェルスクリプトにまとめてみました。(接続情報はダミー)

#!/bin/sh

HOSTNAME=192.0.2.24
USERNAME=girigiribauer
PASSWORD=passwordhere
SOURCE="path/to/source_dir"
DIST="/path/to/target_dir"

lftp -d -u $USERNAME,$PASSWORD $HOSTNAME -e "\
  mirror \
  --reverse \
  --delete \
  --only-newer \
  --verbose \
  -X .DS_Store \
  $SOURCE \
  $DIST; \
  exit"

後半が mirror コマンドのオプションですが、 reverse はアップロードを意味します。

色々オプションあるので詳しくはヘルプを見た方が良いのですが、 lftp の方のヘルプにはあまり詳しく載ってませんので lftp コマンドをそのまま実行して対話形式にしてから help mirror とすることで mirror コマンドの help を開くことができます。

% lftp
lftp :~> help mirror
Usage: mirror [OPTS] [remote [local]]

Mirror specified remote directory to local directory

 -c, --continue         continue a mirror job if possible
 -e, --delete           delete files not present at remote site
     --delete-first     delete old files before transferring new ones
 -s, --allow-suid       set suid/sgid bits according to remote site
     --allow-chown      try to set owner and group on files
     --ignore-time      ignore time when deciding whether to download
 -n, --only-newer       download only newer files (-c won't work)
 -r, --no-recursion     don't go to subdirectories
 -p, --no-perms         don't set file permissions
     --no-umask         don't apply umask to file modes
 -R, --reverse          reverse mirror (put files)
 -L, --dereference      download symbolic links as files
 -N, --newer-than=SPEC  download only files newer than specified time
 -P, --parallel[=N]     download N files in parallel
 -i RX, --include RX    include matching files
 -x RX, --exclude RX    exclude matching files
                        RX is extended regular expression
 -v, --verbose[=N]      verbose operation
     --log=FILE         write lftp commands being executed to FILE
     --script=FILE      write lftp commands to FILE, but don't execute them
     --just-print, --dry-run    same as --script=-

When using -R, the first directory is local and the second is remote.
If the second directory is omitted, basename of first directory is used.
If both directories are omitted, current local and remote directories are used.

今回は、手元のファイルのが新しい場合に動作し、 なおかつ手元で削除したファイルも同期を取りたいので、 –delete と –only-newer オプションをつけました。

まとめ

FTP だけでも rsync にある程度近いことは出来ました。

ただ、 dry-run 相当のオプションが探した限りなかったので、 実際に試しながら正しく動作しているか確認することになるので、 そこはちょっと怖いところではありますね・・・。

2016/09/30追記

さーせん、dry-run オプションありました・・・

–just-print, –dry-run same as –script=- って上にあるじゃん、自分の目はフシ穴か・・・

2016/09/30追記ここまで

FTP のみという縛りがあったとしても、コマンド1つで転送できるようにしておけば、 バージョン管理などと連携してフックさせることも可能となり、 精神衛生的にも良いかと思います。

参考URL

この記事は書かれてから1年以上が経過しており、最新の情報とは異なる可能性があります

もし記事内に誤りなどございましたら、 @girigiribauer @girigiribauer.com までご一報いただけると助かります。

Related articles