LinuxからWindows共有フォルダ、というかSMBサーバにアクセスできると便利ですよね。
最近はUbuntuなどのよく使われているディストリビューションなら、バンドルされているファイラが標準で
サポートしていたりしますが、今回はコマンドラインからマウントすることにします。
もくじ:
UbuntuからWindows共有フォルダをマウントする
Windowsユーザにはあまり馴染みのないフォルダマウント。ファイルシステムの機能で、この場合はファイルサーバ上にある特定のWindows共有フォルダを、あたかもローカルのディレクトリ以下に存在するようにリンクさせることができます。
一旦マウントすると、以降はローカルのパスを指定してファイルサーバにある共有フォルダを操作できます。
準備
だいたいのディストリビューションならmount
コマンドが使えますが、Windows共有フォルダ(SMB)を扱う場合には追加のセットアップが必要だと思います。
下記はUbuntuでの例です。
1 | $ sudo apt install cifs-utils |
マウント
マウントするには、mount
コマンドに-t cifs
オプションをつけて実行します。
1 2 | $ sudo mkdir /mnt/tmp $ sudo mount -t cifs -o username=USER,password=PASSWORD //smbserver/shared/dir /mnt/tmp |
この例では、ファイルサーバ側のパスが//smbserver/shared/dir
で、ローカルの/mnt/tmp
ディレクトリ(既存のもの)にマウントしています。
コマンドの実行には管理者権限が必要です。
ファイルサーバ側でアクセス管理がされている場合は上記のようにアカウントを指定します。この例ではユーザ名USER
、パスワードPASSWORD
を使って接続しています。
リモートのパスとローカルパスが同じディレクトリを指すことになるので、この例では/mnt/tmp
ディレクトリ以下に、//smbserver/shared/dir
ディレクトリの中身(下位のファイルおよびサブディレクトリ)が接続されます。
接続先のWindowsによっては、SMBのバージョンを選ぶ場合があります。デフォルト値はSMBv1のようなので、最近のバージョンが接続先だった場合、IO Errorになることがあります。その場合はvers
オプションでクライアント側のバージョンを指定することで解決するかもしれません。
Windows 7ならvers=2.1
、Windows 10ならvers=3.0
を使うとうまくいくかも。
1 | $ sudo mount -t cifs -o username=USER,password=PASSWORD,vers=2.1 //smbserver/shared/dir /mnt/tmp |
また、日本語のパスが文字化けする場合はiocharset
を指定してみて下さい。近頃の環境ならUTF-8で問題ないはず。これも最近の環境では指定しない場合IO Errorを出したことがありました。
1 | $ sudo mount -t cifs -o username=USER,password=PASSWORD,iocharset=utf8 //smbserver/shared/dir /mnt/tmp |
ただ、私が試した環境ではUTF-8を使うのに必要な共有ライブラリが見つからない旨のエラーが出たので、パッケージを入れなおしたら解決しました。
1 2 | $ sudo apt install linux-generic $ sudo reboot |
アンマウント
不要になった場合はマウントを解除(アンマウント)しておきましょう。
アンマウントする際はumount
コマンドにローカルのパスを指定します。
1 | $ sudo umount /mnt/tmp |
こちらも管理者権限が必要です。
Pythonで自動化する
単純に外部プロセスとして呼び出す程度で良ければ、Pythonで上記のマウントを自動化できます。
スクリプト例はこんな感じ。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | import shlex import shutil import subprocess from time import sleep from getpass import getpass def _mount(user, passwd, remote_dir, local_dir): comline = 'sudo mount -t cifs -o username={},password={},vers=2.1,iocharset=utf8 "{}" {}'.format( user, passwd, remote_dir, local_dir) res = subprocess.check_output(shlex.split(comline)) sleep(2) def _unmount(local_dir): sleep(2) comline = "sudo umount {}".format(local_dir) res = subprocess.check_output(shlex.split(comline)) # settings remote_path = "//192.168.100.12/shared/dir" local_path = "/mnt/tmp" copy_src = "/home/user/src" user_ = "user" pass_ = getpass() # copy local dir to remote _mount(user_, pass_, remote_path, local_path) shutil.copytree(copy_src, os.path.join(local_path, os.path.basename(copy_src))) _unmount(local_path) |
以下、簡単に詳細を書いておきます。
マウント(subprocess)
基本はsubprocess
モジュールでmount
コマンドを実行するだけです。
1 2 3 4 | comline = 'sudo mount -t cifs -o username={},password={},iocharset=utf8 "{}" {}'.format( user, passwd, remote_dir, local_dir) res = subprocess.check_output(shlex.split(comline)) sleep(2) |
ファイルサーバにアクセスする際のパスワードはgetpass
モジュールを使ってスクリプト実行時に入力させます。
アンマウントするときもやり方は同じですが、すぐ操作するとビジーになっていることがあるため、マウント・アンマウントの前後でスリープtime.sleep()
を入れています。
コピー(shutil)
ローカルのファイルシステムを扱うときと同じように、shutil
モジュールを使ってディレクトリをまるごとコピーしています。
ローカルのあるディレクトリを指定し、同じ名前でマウント先にコピーしていますが、ファイルサーバ上のリモートパスがマウントされているので、特にファイルサーバであることを意識せずに操作できるという寸法です。
1 | shutil.copytree(copy_src, os.path.join(local_path, os.path.basename(copy_src))) |
shutil.copytree()
では、コピー先に存在しないディレクトリを指定する仕様なので、実行時に親ディレクトリまで作っておきます。
おわり。