Windows上のcurlでftpサーバーから日本語名のファイルをダウンロードする
Zenn初投稿です。まだまだ未熟者ですがよろしくお願いいたします。
Git for Windows (Git BASH) 付属のcurlでftpサーバーからファイルをダウンロードしようとしたのですが、日本語名のファイルだと「ファイルが見つかりません」と言われてしまいました。
四苦八苦した結果、いくつか対処法を見つけたので記事にしてみました。
curl: (78) The file does not exist
curlでftpサーバーからファイルをダウンロードするため、下記のようなスクリプトを書きました。
#!/bin/bash
set -eu
source './.env'
curl --show-error --silent \
--ftp-method 'nocwd' --ssl-reqd --insecure \
--remote-name \
--user "${USERNAME}:${PASSWORD}" \
'ftp://ftp.example.com/data/テスト.txt'
Git for Windowsインストール済みの環境でGit BASHからスクリプトを実行したところ、下記のエラーが出てダウンロードができませんでした。
curl: (78) The file does not exist
もちろん、ファイルはサーバー上に存在しています。
Ubuntu上で同じスクリプトを実行したところ、問題なくファイルをダウンロードできました。
原因
curlの公式リポジトリで回答がされていました。
どうやらWindows版のcurlでは必ずしもUnicodeがサポートされているとは限らないようです。
Unicodeがサポートされているかどうかは、バージョン情報のFeatures:
で始まる行の中にUnicode
の記述があるかどうかで確認できます。
上記test_1.sh
を実行したGit for Windowsとcurlのバージョンは下記の通りです。
$ git --version
git version 2.45.2.windows.1
$ curl --version
curl 8.8.0 (x86_64-w64-mingw32) libcurl/8.8.0 Schannel zlib/1.3.1 brotli/1.1.0 zstd/1.5.6 libidn2/2.3.7 libpsl/0.21.5 libssh2/1.11.0
Release-Date: 2024-05-22
Protocols: dict file ftp ftps gopher gophers http https imap imaps ipfs ipns ldap ldaps mqtt pop3 pop3s rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: alt-svc AsynchDNS brotli HSTS HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM PSL SPNEGO SSL SSPI threadsafe UnixSockets zstd
Features:
で始まる行の中にUnicode
の記述がないため、Git for Windows付属のcurlではUnicodeがサポートされていないことがわかりました。
対処法
Windows付属のcurl.exeを利用する
実は最近のWindowsにはcurlがプリインストールされています。
PowerShellを立ち上げて確認したcurlのバージョンは下記の通りです。
PS C:\> curl.exe --version
curl 8.4.0 (Windows) libcurl/8.4.0 Schannel WinIDN
Release-Date: 2023-10-11
Protocols: dict file ftp ftps http https imap imaps pop3 pop3s smtp smtps telnet tftp
Features: AsynchDNS HSTS HTTPS-proxy IDN IPv6 Kerberos Largefile NTLM SPNEGO SSL SSPI threadsafe Unicode UnixSockets
curl.exeの.exeは省略できません。
.exe
を省略して実行すると、下記の通りエラーが出てしまいます。
PowerShellではcurlのエイリアスにcurl.exe
ではなくInvoke-WebRequest
というコマンドレットが設定されているためです。
PS C:\> curl --version
curl : リモート名を解決できませんでした。: '--version'
発生場所 行:1 文字:1
+ curl --version
+ ~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest]、WebException
+ FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand
Features:
で始まる行の中にUnicode
の記述があるため、このcurlを使えば良さそうです。
下記のようなスクリプトを書いてPowerShellから実行したところ、無事に日本語名のファイルをダウンロードできました。
# .env の読み込み
Get-Content -LiteralPath '.\.env' | Where-Object -FilterScript {
$_ -ne '' -and $_ -notlike '#*'
} | ForEach-Object -Process {
$name, $value = $_ -split '=', 2
Set-Variable -Name $name -Value $value
}
curl.exe --show-error --silent `
--ftp-method 'nocwd' --ssl-reqd --insecure `
--remote-name `
--user "${USERNAME}:${PASSWORD}" `
'ftp://ftp.example.com/data/テスト.txt'
-s
, --silent
の代わりに-v
, --verbose
を付けて実行すると出力の日本語部分が文字化けしますが、ファイルのダウンロードは問題なくできるため深追いしないことにしました。
-K
, --config
オプションを利用する
Windows用にわざわざPowerShellスクリプトを用意したくない、どうしてもGit for Windows付属のcurlを使いたい、などの場合は-K
, --config
オプションを利用する方法もあります。
curlのコマンドライン引数をテキストファイルに記述し、そのファイルをcurlの-K
, --config
オプションで指定することで、日本語名のファイルでも正しく認識してくれるようになります。
下記のようなスクリプトを書いてGit BASHから実行したところ、無事に日本語名のファイルをダウンロードできました。
#!/bin/bash
set -eu
source './.env'
curl --config './config_test_2.txt' \
--user "${USERNAME}:${PASSWORD}"
show-error
silent
ftp-method = "nocwd"
ssl-reqd
insecure
remote-name
url = "ftp://ftp.example.com/data/テスト.txt"
ただし、この方法には致命的な欠陥があります。
ls
でダウンロードしたファイルを確認してみましょう。
$ ls
config_test_2.txt test_2.sh* 繝・せ繝・txt
ファイル名が文字化けしてしまいます。
Git BASH (mintty) の設定を変更する、chcp.com
でコードページを変更する、などいろいろ試しましたが、この文字化けを解消することはできませんでした。
仕方がないので、-O
, --remote-name
の代わりに-o
, --output
でダウンロード後のファイル名を指定します。
@@ -5,3 +5,3 @@
insecure
-remote-name
+output = "test_output.txt"
url = "ftp://ftp.example.com/data/テスト.txt"
test_2.sh
, ls
を再実行し、ファイル名が指定した通りになっていることを確認します。
$ ls
config_test_2.txt test_2.sh* test_output.txt
WSL2をインストールする
WSL2は利用したことがないのですが、おそらくこれが最善な対処法でしょう。
機会があったらぜひWSL2にも触れてみたいです。
Ubuntu上での実行結果
Ubuntu上では、上記test_1.sh
, test_2.sh
ともに文字化けすることなく日本語名のファイルをダウンロードできました。
利用したcurlのバージョンは下記の通りです。
$ curl --version
curl 7.68.0 (x86_64-pc-linux-gnu) libcurl/7.68.0 OpenSSL/1.1.1f zlib/1.2.11 brotli/1.0.7 libidn2/2.2.0 libpsl/0.21.0 (+libidn2/2.2.0) libssh/0.9.3/openssl/zlib nghttp2/1.40.0 librtmp/2.3
Release-Date: 2020-01-08
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp scp sftp smb smbs smtp smtps telnet tftp
Features: AsynchDNS brotli GSS-API HTTP2 HTTPS-proxy IDN IPv6 Kerberos Largefile libz NTLM NTLM_WB PSL SPNEGO SSL TLS-SRP UnixSockets
Unicode
はWindows版限定のfeatureなので、Ubuntu版curlのバージョン情報には記載がありません。
まとめ
この記事では、Windows上のcurlでftpサーバーから日本語名のファイルをダウンロードする方法を紹介しました。
Windowsのみの対応でよければ、Windows付属のcurl.exeを利用して、バッチファイルかPowerShellのスクリプトを書くことで対処できます。
どうしてもGit for Windows付属のcurlを使いたい場合は、-K
, --config
オプションを利用する方法もありますが、ダウンロードしたファイルの名前が文字化けするという問題があります。
可能であれば、WSL2をインストールして、Windows上でもLinux版curlを利用することが最善な対処法でしょう。
Discussion