ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

curl 命令行 `--upload-file`(-T):把本地文件上传到远端 URL 的完整技术指南

curl 命令行 `--upload-file`(-T):把本地文件上传到远端 URL 的完整技术指南 curl 命令行--upload-file-T把本地文件上传到远端 URL 的完整技术指南【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl本篇围绕 curl 命令行选项--upload-file短形式-T展开基于 官方文档 并结合 curl 源码实现完整讲解上传文件时的 URL 文件名补全规则、stdin 上传-与.的区别、HTTP 下自动切换 PUT 方法的底层机制以及多文件 glob 批量上传与 8.21.0 引入的具名 glob 用法。读完后你可以直接用-T完成 FTP、HTTP(S)、IMAP、SMTP 等协议下的文件上传并能从源码层面理解 curl 是如何配对-T与 URL 的。选项速览属性值长选项--upload-file短选项-T参数file本地文件路径-/.表示 stdin空参数表示“不上传”作用将本地文件上传到指定 URL 指向的远端位置引入版本curl 4.0作用粒度per-URL每个-T与一个 URL 配对所属分类important / upload / imap相关选项--get、--head、--request、--data该选项在 curl 的参数表中注册于 src/tool_getparam.c{upload-file, ARG_FILE, T, C_UPLOAD_FILE},ARG_FILE表明它接收一个文件参数T即短形式-T。文档同时列出它属于important类帮助输出中会重点展示的核心上传选项并标注了imap分类——用-T上传邮件正文是 IMAP 协议的典型用法。基本用法与示例文档给出的全部示例均可直接复制运行# 1. 最基础把本地 file 上传到 $URL curl -T file $URL # 2. FTP用范围 glob 上传 1000 张图片 curl -T img[1-1000].png ftp://ftp.example.com/ # 3. HTTP把多个文件上传到同一 URL注意 URL 的 glob 写法 curl --upload-file {file1,file2} $URL # 4. 每个 -T 与一个 URL 一一对应 curl -T file -T file2 $URL $URL要点说明一个-T对一个 URL命令行上可以出现多个--upload-file它们按出现顺序与 URL 列表一一配对分别决定“上传什么、上传到哪里”。这正是文档元数据中Multi: per-URL的含义。glob 支持--upload-file的参数本身支持 glob 展开{1,2,3}、[1-1000]等与 URL 侧同一套 glob 语法因此可以把一组本地文件上传到同一个远端位置。在 verbose 输出-v中curl 会把这种请求标注为PUT (-T, --upload-file)见 src/tool_helpers.c。源码视角-T 与 URL 如何配对-T的解析函数是parse_upload_file()位于 src/tool_getparam.c。它的核心逻辑是维护一个config-url_ul节点指针getout节点链表始终指向第一个“尚未被-T占用”的 URL 节点若当前节点已有uploadset标记则沿链表后移寻找空闲节点没有空闲节点时通过new_getout(config)新建一个命中后设置url-uploadset TRUE并保存文件名到url-infileDENY_BLANK表示参数不能为空白-被允许保留为字符串后续再按 stdin 处理。/* src/tool_getparam.c:1494 附近 */ if(!config-url_ul) config-url_ul config-url_list; if(config-url_ul) { /* 跳过已填充的节点寻找空闲节点 */ while(config-url_ul config-url_ul-uploadset) config-url_ul config-url_ul-next; } ... url-uploadset TRUE; /* mark -T used */ if(!*nextarg) url-noupload TRUE; /* 空参数 显式取消该 URL 的上传 */ else err getstr(url-infile, nextarg, DENY_BLANK);从这段代码可以确认两件事-T的配对是严格的顺序配对另外--upload-file 空参数会被解析为noupload TRUE即显式声明“该 URL 不上传”。URL 没有文件名时自动追加本地文件名这是--upload-file最容易踩坑的行为文档原文明确规定If there is no file part in the specified URL, curl appends the local file name to the end of the URL before the operation starts. You must use a trailing slash (/) on the last directory to prove to curl that there is no filename or curl thinks that your last directory name is the remote filename to use.也就是说如果 URL 路径没有文件名部分以/结尾或无路径curl 会在操作开始前把本地文件名追加到 URL 末尾作为远端文件名当最后一级是目录时必须用结尾斜杠/来证明它是目录否则 curl 会把最后一段当作远端文件名。例如ftp://host/pub/与ftp://host/pub的上传目标文件名不同。同时文档规定追加时 curl 只取本地路径中最右侧/或\右边的部分左侧路径一律忽略。因此curl -T /tmp/report.xlsx ftp://ftp.example.com/的远端文件名是report.xlsx而非/tmp/report.xlsx。源码视角add_file_name_to_url()这一行为由 src/tool_operhlp.c 中的add_file_name_to_url()实现它在上传流程的setup_transfer_upload()src/tool_operate.c中被调用/* src/tool_operate.c:1324 附近 */ if(per-uploadfile) { if(stdin_upload(per-uploadfile)) check_stdin_upload(config, per); else { /* We have specified a file to upload and it is not - */ result add_file_name_to_url(per-curl, per-url, per-uploadfile);add_file_name_to_url()的关键步骤见 src/tool_operhlp.c用 CURLU 句柄解析 URL分别取出CURLUPART_PATH与CURLUPART_QUERY若 URL 带 query?之后有内容直接不做修改并返回——避免破坏带参数的 URL检查路径最后一个/之后是否还有字符ptr strrchr(path, /); if(!ptr || !*ptr)表示“没有文件名部分”才进入追加逻辑追加时执行文档所述的“取最右斜杠后部分”规则且同时兼容 Windows 反斜杠/* 只取最右侧 / 或 \ 右边的部分 */ const char *filep strrchr(filename, /); const char *file2 strrchr(filep ? filep : filename, \\); ... /* 文件名做 URL 编码后拼接到路径上 */ encfile curl_easy_escape(curl, filep, 0); newpath curl_maprintf(%s%s, path, encfile); /* path 以 / 结尾时 */注意追加前会用curl_easy_escape()对文件名做 URL 编码所以本地文件名含空格、中文等字符时会被正确转义不需要手动处理。用 stdin 上传-与.的区别文档规定两种特殊文件名-短横线用 stdin 代替文件上传.句点同样使用 stdin但是非阻塞模式允许在上传 stdin 的同时读取服务端输出。源码中对这两种符号的判定集中在 src/tool_operhlp.cbool stdin_upload(const char *uploadfile) { return !strcmp(uploadfile, -) || !strcmp(uploadfile, .); }-与.的差异体现在 src/tool_operate.c 的非阻塞分支以及check_stdin_upload()src/tool_operate.c中的一条重要告警/* src/tool_operate.c:1184 附近 */ warnf(Using --anyauth or --proxy-anyauth with upload from stdin will make the transfer stop at the first unauthenticated response.);也就是说stdin 上传 --anyauth或--proxy-anyauth组合会使传输在收到第一个未认证响应时停止——因为认证重试需要重放请求而 stdin 只能消费一次。对交互式认证场景应优先用具体认证方式如--basic、--digest代替--anyauth。典型 stdin 上传用法# 把文件内容经管道/重定向从 stdin 上传 cat report.xlsx | curl -T - ftp://ftp.example.com/report.xlsx # 非阻塞 stdin 上传.上传期间可同时读服务端回显 curl -T . https://upload.example/ bigfile.binHTTP(S) 下的行为自动使用 PUT文档明确写道“If this option is used with an HTTP(S) URL, the PUT method is used.” 这条规则在 libcurl 命令行层的实现链路是src/config2setopts.c 中只要该 URL 配了上传文件就开启CURLOPT_UPLOADmy_setopt_long(curl, CURLOPT_UPLOAD, !!per-uploadfile);libcurl 内部据此把 HTTP 方法设为 PUT。在 lib/http.c 可以看到httpreq HTTPREQ_PUT;的赋值随后在 lib/http.c 的case HTTPREQ_PUT: /* Lets PUT the data to the server! */分支中真正发送 PUT 请求。因此不需要再配合--request PUT-T本身就隐含了 PUT而文档 See-also 中列出的--request可用于显式覆盖例如用--request POST强制 POST 上传。文件大小如何告知服务器上传前 curl 会探测本地文件大小并设置为CURLOPT_INFILESIZE_LARGE这样 HTTP PUT 能携带准确的Content-Length。相关逻辑在 src/tool_operate.c/* src/tool_operate.c:268 附近VMS 特判从略 */ if(curlx_stat(per-uploadfile, fileinfo) 0) { ... per-infd curlx_open(per-uploadfile, O_RDONLY | CURL_O_BINARY); ... uploadfilesize fileinfo.st_size; } ... if(uploadfilesize ! -1) my_setopt_offt(per-curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize);文件以二进制模式CURL_O_BINARY打开保证了 FTP 二进制传输与 HTTP 原始字节上传的完整性stat 失败如 stdin、管道时uploadfilesize保持 -1表示长度未知这与-/.stdin 上传的“流式”语义一致。多文件与 glob 批量上传--upload-file的参数支持 URL 同款 glob把多个本地文件打到同一个远端位置# 三个文件上传到同一 FTP 目录远端文件名各自独立 curl --upload-file file{1,2,3} ftp://ftp.example/ # 文档元数据中的等价写法 curl --upload-file {file1,file2} $URL上传侧 glob 的推进发生在 src/tool_operate.c当某个 URL 对应的本地文件名用完后通过glob_next_url(state-uploadfile, state-inglob)取下一个 glob 展开项直到全部上传完毕。8.21.0 新增具名 globnamed globs自 curl 8.21.0 起上传文件名 glob 支持命名并在同一命令行中被其他选项引用——引用方式与 URL 侧的具名 glob 完全相同。文档给出的例子是把三个文件上传到同一个固定 HTTP URL并把各自的响应分别存到不同文件curl -T file{num1,2,3} \ https://upload.example/ -o response-#num解释file{num1,2,3}是具名 globnum是变量名展开时依次取值 1、2、3-o response-#num中的#num引用同一个变量于是三次传输分别写入response-1、response-2、response-3上传目标https://upload.example/是固定的不随 glob 变化。这解决了“批量上传同一端点、分别保存响应”这类此前难以在单条命令内表达的需求。使用 SMTP 时的格式要求文档最后一段针对 SMTP 上传即“发邮件”场景给出硬性约束When uploading to an SMTP server (aka sending email): the uploaded data is assumed to be RFC 5322 formatted. It has to feature the necessary set of headers and mail body formatted correctly by the user as curl does not transcode nor encode it further in any way.即上传给 SMTP 服务器的数据必须已经是完整的 RFC 5322 邮件格式含必要的头部与正文curl 不会做任何转码、编码或格式补全。准备本地文件时应自行写好From:、To:、Subject:等头与正文。常见问题与注意事项结尾斜杠决定远端文件名ftp://host/dir会把dir当作远端文件名当 URL 已有文件名部分时本地文件名被忽略要上传到dir目录下且保留本地文件名必须写ftp://host/dir/。这是由add_file_name_to_url()中“仅当最后/后无字符才追加”的判定逻辑直接决定的见前文源码分析。本地路径只取文件名部分C:\data\a\report.txt、/data/a/report.txt上传后的远端名都只有report.txtWindows 反斜杠分隔符在 src/tool_operhlp.c 中被显式处理。stdin 只能消费一次配合--anyauth会出现“认证重试失败即停止”的告警行为src/tool_operate.c交互式认证请避免该组合。HTTP 下是 PUT 而非 POST需要 POST 上传时用--data/-F系列选项--upload-file的语义就是“把整个本地文件按原字节流 PUT/上传”。per-URL 配对-T a -T b URL1 URL2中a→URL1、b→URL2想上传多个文件到同一 URL用 globfile{1,2}而不是重复 URL。相关文档与源码索引本文档原型docs/cmdline-opts/upload-file.md —— 实际路径为 docs/cmdline-opts/upload-file.md参数注册与-T/URL 配对解析src/tool_getparam.cURL 文件名追加与 Windows 路径处理src/tool_operhlp.c上传流程编排、stdin 处理与文件大小探测src/tool_operate.c、src/tool_operate.cCURLOPT_UPLOAD到 PUT 的映射src/config2setopts.c、lib/http.c上传缓冲区与上传状态字段定义lib/urldata.h适用前提本文内容以当前仓库curl 主仓库文档与源码为准具名 glob 示例要求 curl ≥ 8.21.0。其余-T基础行为自 curl 4.0 起长期稳定。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表