如何在 Bash 脚本中将 (FTP) 文件上传到服务器?

Posted

技术标签:

【中文标题】如何在 Bash 脚本中将 (FTP) 文件上传到服务器?【英文标题】:How can I upload (FTP) files to server in a Bash script? 【发布时间】:2010-12-26 01:06:18 【问题描述】:

我正在尝试编写一个将文件上传到服务器的 Bash 脚本。我怎样才能做到这一点?使用 Bash 脚本是否合适?

【问题讨论】:

解决方案不是针对 ftp 协议,而是针对 ssh。 【参考方案1】:

以下是两个答案。首先是建议使用更安全/更灵活的解决方案,例如 ssh/scp/sftp。二是讲解如何以批处理方式运行ftp。

安全的解决方案:

您确实应该为此使用 SSH/SCP/SFTP 而不是 FTP。 SSH/SCP 的好处是更安全,并且可以使用公钥/私钥,无需用户名或密码即可运行。

您可以发送单个文件:

scp <file to upload> <username>@<hostname>:<destination path>

或整个目录:

scp -r <directory to upload> <username>@<hostname>:<destination path>

有关设置密钥和使用 RSYNC 将文件移动到服务器的更多详细信息,如果您有很多文件要移动,或者如果您有时在一组随机文件中只得到一个新文件,这很有用,请采取看看:

http://troy.jdmz.net/rsync/index.html

您也可以在 ssh 到服务器后执行单个命令:

来自man ssh

ssh [...snipped...] hostname [command] 如果指定了命令,则为 在远程主机而不是登录 shell 上执行。

所以,一个示例命令是:

ssh username@hostname.example bunzip file_just_sent.bz2

如果您可以使用带有密钥的 SFTP 来获得安全连接的好处,那么我使用了两个技巧来执行命令。

首先,您可以使用 echo 和管道传递命令

echo "put files*.xml" | sftp -p -i ~/.ssh/key_name username@hostname.example

您还可以使用带有-b 参数的批处理文件:

sftp -b batchfile.txt ~/.ssh/key_name username@hostname.example

一个 FTP 解决方案,如果你真的需要它:

如果您了解 FTP 不安全且受到更多限制,并且您真的很想编写脚本...

http://www.stratigery.com/scripting.ftp.html 上有一篇很棒的文章

#!/bin/sh
HOST='ftp.example.com'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'

ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
binary
put $FILE
quit
END_SCRIPT
exit 0

-n 到 ftp 确保命令不会尝试从当前终端获取密码。另一个花哨的部分是使用heredoc:&lt;&lt;END_SCRIPT 启动heredoc,然后在行首的完全相同的END_SCRIPT 单独结束heredoc。 binary 命令会将其设置为二进制模式,这有助于您传输文本文件以外的内容。

【讨论】:

我想这样做!您能否详细说明我如何做到这一点?上传文件后,我需要用 ssh 做一些事情。这可以在一个会话中完成吗? 虽然这对 OP 来说是有用的建议,但它不应该是公认的答案。它没有回答原始问题(通过 Google 找到) 其他一些发布者在 FTP 命令中添加了二进制模式(即bin)。由于您的答案已被接受,因此我建议您也将其添加到您的答案中。 感谢您的回答,包括 ssh 和 FTP。我不明白关于 FTP 的大惊小怪。也许我正在为一个网站在 FTP 上的客户工作,我只是不在乎,我只关心客户想用他的网站做什么。 也可以输入hash以某种方式显示ftp传输的进度。此外,您通常会在文件结尾看到 &lt;&lt;EOF【参考方案2】:

您可以使用heredoc 来执行此操作,例如

ftp -n $Server <<End-Of-Session
# -n option disables auto-logon

user anonymous "$Password"
binary
cd $Directory
put "$Filename.lsm"
put "$Filename.tar.gz"
bye
End-Of-Session

所以ftp 进程以标准输入为基础,直到End-Of-Session。这是生成任何进程的有用提示,而不仅仅是ftp!请注意,这样可以避免生成一个单独的进程(echo、cat 等)。这不是主要的资源节省,但值得牢记。

【讨论】:

这完全令人困惑。我如何摆脱这个会话结束的事情?为什么不直接输入到没有那个的ftp提示符呢? @erikb85 - 这用于脚本,而不是(必须)用于交互使用。 heredoc 将自动在您的“会话结束”标记上注册一个动作(您可能会使用 EOF 或类似的)【参考方案3】:

ftp 命令不是为脚本设计的,所以控制它很尴尬,并且获得它的退出状态更尴尬。

Curl 是可编写脚本的,并且还有一个优点是您以后只需修改 URL 即可轻松切换到其他协议。如果您将 FTP 凭据放入您的 .netrc,您可以这样做:

# Download file
curl --netrc --remote-name ftp://ftp.example.com/file.bin
# Upload file
curl --netrc --upload-file file.bin ftp://ftp.example.com/

如果必须,您可以直接在命令行上使用--user username:password 而不是--netrc 指定用户名和密码。

【讨论】:

这是更简单的解决方案。 curl 默认情况下未安装在Ubuntu MATE 20.04(Focal Fossa)上。 (但lftp 也不是。)【参考方案4】:

安装 ncftpput 和 ncftpget。它们通常是同一个包的一部分。

【讨论】:

命令行是:"ncftpput -u username -p password server.org /path/filename.blah" 注意连接不会被加密,密码会以明文形式发送。 @Adam “连接不会被加密”等是使用 FTP 的结果,这是在问题中指定的。无论您使用什么 FTP 客户端,它都会发生。【参考方案5】:

一行命令:

ftp -in -u ftp://username:password@servername/path/to/ localfile

【讨论】:

@erikbwork -u is: " -u URL file [...] - 将命令行上的文件上传到 URL,其中 URL 是自动获取支持的 ftp URL 类型之一(使用单个文件上传的可选目标文件名),文件是要上传的一个或多个本地文件。” 您使用的是哪个版本的 ftp?它不适用于 ubuntu 18【参考方案6】:

使用它来将文件上传到远程位置:

#!/bin/bash
#$1 is the file name
#usage:this_script <filename>
HOST='your host'
USER="your user"
PASSWD="pass"
FILE="abc.php"
REMOTEPATH='/html'

ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
cd $REMOTEPATH
put $FILE 
quit
END_SCRIPT
exit 0

【讨论】:

这是不使用 .netrc 的一个相当晚的答案,但是它可以扩展删除并使我们中的许多人摆脱 wput/wget/wdel 分段违规漏洞。 请使用 USER 和 PASS 登录。 解释一下。例如,它与之前的答案有何不同?【参考方案7】:
#/bin/bash
# $1 is the file name
# usage: this_script  <filename>
IP_address="xx.xxx.xx.xx"
username="username"
domain=my.ftp.domain
password=password

echo "
 verbose
 open $IP_address
 USER $username $password
 put $1
 bye
" | ftp -n > ftp_$$.log

【讨论】:

你的意思是 echo "..." | ftp -n | ftp_$$.log ? 目前这会写入文件 'ftp' 并且不会产生 ftp 进程 @Yossarian:只有第一个&gt; 应该是| @ennuikiller:等号周围有空格,这是 Bash 不喜欢的。此外,以明文形式硬编码密码也是一个坏主意。 我确定密码问题仅用于说明目的【参考方案8】:

将文件放在根目录下的工作示例...看,这很简单:

#!/bin/sh
HOST='ftp.users.qwest.net'
USER='yourid'
PASSWD='yourpw'
FILE='file.txt'

ftp -n $HOST <<END_SCRIPT
quote USER $USER
quote PASS $PASSWD
put $FILE
quit
END_SCRIPT
exit 0

【讨论】:

#!/bin/bash #$1 是文件名 #usage:this_script HOST='yourhost' USER="youruser" PASSWD="yourpass" FILE="abc.php" REMOTEPATH ='/html' ftp -n $HOST 【参考方案9】:

没有必要让事情复杂化。这应该有效:

#/bin/bash
echo "
 verbose
 open ftp.mydomain.net
 user myusername mypassword
 ascii
 put textfile1
 put textfile2
 bin
 put binaryfile1
 put binaryfile2
 bye
" | ftp -n > ftp_$$.log

或者如果你有很多文件,你可以使用mput...

【讨论】:

【参考方案10】:

如果您想在“for”中使用它来复制最后生成的文件以进行日常备份...

j=0
var="`find /backup/path/ -name 'something*' -type f -mtime -1`"
# We have some files in $var with last day change date

for i in $var
  do
  j=$(( $j + 1 ))
  dirname="`dirname $i`"
  filename="`basename $i`"
  /usr/bin/ftp -in >> /tmp/ftp.good 2>> /tmp/ftp.bad << EOF
    open 123.456.789.012
    user user_name passwd
    bin
    lcd $dirname
    put $filename
    quit
  EOF      # End of ftp
done       # End of 'for' iteration

【讨论】:

【参考方案11】:
echo -e "open <ftp.hostname>\nuser <username> <password>\nbinary\nmkdir New_Folder\nquit" | ftp -nv

【讨论】:

解释一下。例如,想法/要点是什么?

以上是关于如何在 Bash 脚本中将 (FTP) 文件上传到服务器?的主要内容,如果未能解决你的问题,请参考以下文章

使用 bash 脚本批量重命名 FTP 服务器上的文件

在c#中将多个文件上传到FTP

数据库备份文件上传到ftp服务器脚本

在批处理文件中将文本文件上传到FTP,该文件具有随机生成的文件名

sh 如何在shell脚本/ bash中将输出附加到文本文件的末尾?

在 EF Core 中将 IFormFile 上传到 FTP