Как написать сценарий загрузки и выгрузки по FTP? - PullRequest
39 голосов
/ 01 июня 2009

Я пытаюсь создать командный файл для загрузки файла на FTP-сервер. Если я ввожу его вручную, он работает нормально, но когда я запускаю командный файл, он останавливается после подключения ... он говорит

connected to domain.com.

220 microsoft ftp server

User(domain.com:(none)):

тогда больше ничего. Какого черта здесь происходит?

Ниже мой пакетный файл:

ftp www.domainhere.com 

user useridhere

passwordhere

put test.txt

bye

pause

Ответы [ 9 ]

66 голосов
/ 02 июня 2009

Разумно было бы хотеть написать сценарий FTP-сессии так, как представлял себе оригинальный постер, и именно в этом может помочь Expect. Пакетные файлы в Windows не могут этого сделать.

Но вместо того, чтобы делать cURL или Expect, вам может быть проще написать сценарий взаимодействия FTP с Powershell. Это другая модель, в которой вы не пишете текст напрямую для отправки на FTP-сервер. Вместо этого вы будете использовать Powershell для управления объектами, которые генерируют диалог FTP для вас.

Загрузить:

$File = "D:\Dev\somefilename.zip"
$ftp = "ftp://username:password@example.com/pub/incoming/somefilename.zip"

"ftp url: $ftp"

$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)

"Uploading $File..."

$webclient.UploadFile($uri, $File)

Скачать:

$File = "c:\store\somefilename.zip"
$ftp = "ftp://username:password@example.com/pub/outbound/somefilename.zip"

"ftp url: $ftp"

$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)

"Downloading $File..."

$webclient.DownloadFile($uri, $File)

Вам нужен Powershell, чтобы сделать это. Если вы не знаете, Powershell - это оболочка типа cmd.exe, которая запускает ваши .bat файлы. Но Powershell запускает файлы .ps1 и немного более мощный. Powershell - это бесплатное дополнение к Windows, которое будет встроено в будущие версии Windows. Получите это здесь .

Источник: http://poshcode.org/1134

26 голосов
/ 01 июня 2009

Создайте командный файл с вашими командами

т.е.: commands.txt

open www.domainhere.com
user useridhere 
passwordhere
put test.txt
bye

Затем запустите FTP-клиент из командной строки: ftp -s: commands.txt

Примечание. Это будет работать для FTP-клиента Windows.

Редактировать: должен был стоять перевод строки после имени пользователя перед паролем.

6 голосов
/ 02 апреля 2011

Я сделал это с помощью PowerShell :

function DownloadFromFtp($destination, $ftp_uri, $user, $pass){
    $dirs = GetDirecoryTree $ftp_uri $user $pass

    foreach($dir in $dirs){
       $path = [io.path]::Combine($destination,$dir)

       if ((Test-Path $path) -eq $false) {
          "Creating $path ..."
          New-Item -Path $path -ItemType Directory | Out-Null
       }else{
          "Exists $path ..."
       }
    }

    $files = GetFilesTree $ftp_uri $user $pass

    foreach($file in $files){
        $source = [io.path]::Combine($ftp_uri,$file)
        $dest = [io.path]::Combine($destination,$file)

        "Downloading $source ..."
        Get-FTPFile $source $dest $user $pass
    }
}

function UploadToFtp($artifacts, $ftp_uri, $user, $pass){
    $webclient = New-Object System.Net.WebClient 
    $webclient.Credentials = New-Object System.Net.NetworkCredential($user,$pass)  

    foreach($item in Get-ChildItem -recurse $artifacts){ 

        $relpath = [system.io.path]::GetFullPath($item.FullName).SubString([system.io.path]::GetFullPath($artifacts).Length + 1)

        if ($item.Attributes -eq "Directory"){

            try{
                Write-Host Creating $item.Name

                $makeDirectory = [System.Net.WebRequest]::Create($ftp_uri+$relpath);
                $makeDirectory.Credentials = New-Object System.Net.NetworkCredential($user,$pass) 
                $makeDirectory.Method = [System.Net.WebRequestMethods+FTP]::MakeDirectory;
                $makeDirectory.GetResponse();

            }catch [Net.WebException] {
                Write-Host $item.Name probably exists ...
            }

            continue;
        }

        "Uploading $item..."
        $uri = New-Object System.Uri($ftp_uri+$relpath) 
        $webclient.UploadFile($uri, $item.FullName)
    }
}

 function Get-FTPFile ($Source,$Target,$UserName,$Password) 
 { 
     $ftprequest = [System.Net.FtpWebRequest]::create($Source) 
     $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password) 
     $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile 
     $ftprequest.UseBinary = $true 
     $ftprequest.KeepAlive = $false 

     $ftpresponse = $ftprequest.GetResponse() 
     $responsestream = $ftpresponse.GetResponseStream() 

     $targetfile = New-Object IO.FileStream ($Target,[IO.FileMode]::Create) 
     [byte[]]$readbuffer = New-Object byte[] 1024 

     do{ 
         $readlength = $responsestream.Read($readbuffer,0,1024) 
         $targetfile.Write($readbuffer,0,$readlength) 
     } 
     while ($readlength -ne 0) 

     $targetfile.close() 
 } 

#task ListFiles {
#   
#    $files = GetFilesTree 'ftp://127.0.0.1/' "web" "web"
#    $files | ForEach-Object {Write-Host $_ -foregroundcolor cyan}
#}

function GetDirecoryTree($ftp, $user, $pass){
    $creds = New-Object System.Net.NetworkCredential($user,$pass)

    $files = New-Object "system.collections.generic.list[string]"
    $folders = New-Object "system.collections.generic.queue[string]"
    $folders.Enqueue($ftp)

    while($folders.Count -gt 0){
        $fld = $folders.Dequeue()

        $newFiles = GetAllFiles $creds $fld
        $dirs = GetDirectories $creds $fld

        foreach ($line in $dirs){
            $dir = @($newFiles | Where { $line.EndsWith($_) })[0]
            [void]$newFiles.Remove($dir)
            $folders.Enqueue($fld + $dir + "/")

            [void]$files.Add($fld.Replace($ftp, "") + $dir + "/")
        }
    }

    return ,$files
}

function GetFilesTree($ftp, $user, $pass){
    $creds = New-Object System.Net.NetworkCredential($user,$pass)

    $files = New-Object "system.collections.generic.list[string]"
    $folders = New-Object "system.collections.generic.queue[string]"
    $folders.Enqueue($ftp)

    while($folders.Count -gt 0){
        $fld = $folders.Dequeue()

        $newFiles = GetAllFiles $creds $fld
        $dirs = GetDirectories $creds $fld

        foreach ($line in $dirs){
            $dir = @($newFiles | Where { $line.EndsWith($_) })[0]
            [void]$newFiles.Remove($dir)
            $folders.Enqueue($fld + $dir + "/")
        }

        $newFiles | ForEach-Object { 
            $files.Add($fld.Replace($ftp, "") + $_) 
        }
    }

    return ,$files
}

function GetDirectories($creds, $fld){
    $dirs = New-Object "system.collections.generic.list[string]"

    $operation = [System.Net.WebRequestMethods+Ftp]::ListDirectoryDetails
    $reader = GetStream $creds $fld $operation
    while (($line = $reader.ReadLine()) -ne $null) {

       if ($line.Trim().ToLower().StartsWith("d") -or $line.Contains(" <DIR> ")) {
            [void]$dirs.Add($line)
        }
    }
    $reader.Dispose();

    return ,$dirs
}

function GetAllFiles($creds, $fld){
    $newFiles = New-Object "system.collections.generic.list[string]"
    $operation = [System.Net.WebRequestMethods+Ftp]::ListDirectory

    $reader = GetStream $creds $fld $operation

    while (($line = $reader.ReadLine()) -ne $null) {
       [void]$newFiles.Add($line.Trim()) 
    }
    $reader.Dispose();

    return ,$newFiles
}

function GetStream($creds, $url, $meth){

    $ftp = [System.Net.WebRequest]::Create($url)
    $ftp.Credentials = $creds
    $ftp.Method = $meth
    $response = $ftp.GetResponse()

    return New-Object IO.StreamReader $response.GetResponseStream()
}

Export-ModuleMember UploadToFtp, DownLoadFromFtp
6 голосов
/ 01 июня 2009

Пакетные файлы не работают таким образом. Они не просто "набирают" все - они запускают системные команды, в данном случае ftp, ждут их возврата и запускают следующую команду ... так что в этом случае интерпретатор просто ждет ftp выйти.

Если вы должны использовать команду ftp, подготовьте файл сценария (например, commands.txt и выполните ftp -s:commands.txt.

Но лучше использовать cURL или скрипт PHP / Perl / Python / любой другой.

2 голосов
/ 22 апреля 2015

Я знаю, что это старый вопрос, но я хотел добавить кое-что к ответам, уже здесь, в надежде помочь кому-то еще.

Вы можете написать команду ftp с опцией -s:filename. Синтаксис - это просто список команд, передаваемых в оболочку ftp, каждая из которых заканчивается новой строкой. На этой странице есть хорошая ссылка на команды, которые можно выполнить с помощью ftp.

Загрузить / скачать всю структуру каталогов

Использование обычного ftp не очень хорошо работает, когда вам нужно скопировать все дерево каталогов на или с FTP-сайта. Таким образом, вы могли бы использовать что-то вроде этого, чтобы справиться с этими ситуациями.

Эти сценарии работают с командой Windows ftp и позволяют загружать и скачивать целые каталоги из одной команды. Это делает его достаточно самостоятельным при использовании в разных системах.

По сути, они отображают структуру каталогов для загрузки / загрузки, выгружают соответствующие команды ftp в файл, а затем выполняют эти команды после завершения сопоставления.

ftpupload.bat

@echo off

SET FTPADDRESS=%1
SET FTPUSERNAME=%2
SET FTPPASSWORD=%3
SET LOCALDIR=%~f4
SET REMOTEDIR=%5

if "%FTPADDRESS%" == "" goto FTP_UPLOAD_USAGE
if "%FTPUSERNAME%" == "" goto FTP_UPLOAD_USAGE
if "%FTPPASSWORD%" == "" goto FTP_UPLOAD_USAGE
if "%LOCALDIR%" == "" goto FTP_UPLOAD_USAGE
if "%REMOTEDIR%" == "" goto FTP_UPLOAD_USAGE

:TEMP_NAME
set TMPFILE=%TMP%\%RANDOM%_ftpupload.tmp
if exist "%TMPFILE%" goto TEMP_NAME 

SET INITIALDIR=%CD%

echo user %FTPUSERNAME% %FTPPASSWORD% > %TMPFILE%
echo bin >> %TMPFILE%
echo lcd %LOCALDIR% >> %TMPFILE%

cd %LOCALDIR%

setlocal EnableDelayedExpansion
echo mkdir !REMOTEDIR! >> !TMPFILE!
echo cd %REMOTEDIR% >> !TMPFILE!
echo mput * >> !TMPFILE!
for /d /r %%d in (*) do (
    set CURRENT_DIRECTORY=%%d
    set RELATIVE_DIRECTORY=!CURRENT_DIRECTORY:%LOCALDIR%=!
    echo mkdir "!REMOTEDIR!/!RELATIVE_DIRECTORY:~1!" >> !TMPFILE!
    echo cd "!REMOTEDIR!/!RELATIVE_DIRECTORY:~1!" >> !TMPFILE!
    echo mput "!RELATIVE_DIRECTORY:~1!\*" >> !TMPFILE!
)

echo quit >> !TMPFILE!

endlocal EnableDelayedExpansion

ftp -n -i "-s:%TMPFILE%" %FTPADDRESS%

del %TMPFILE%

cd %INITIALDIR%

goto FTP_UPLOAD_EXIT

:FTP_UPLOAD_USAGE

echo Usage: ftpupload [address] [username] [password] [local directory] [remote directory]
echo.

:FTP_UPLOAD_EXIT

set INITIALDIR=
set FTPADDRESS=
set FTPUSERNAME=
set FTPPASSWORD=
set LOCALDIR=
set REMOTEDIR=
set TMPFILE=
set CURRENT_DIRECTORY=
set RELATIVE_DIRECTORY=

@echo on

ftpget.bat

@echo off

SET FTPADDRESS=%1
SET FTPUSERNAME=%2
SET FTPPASSWORD=%3
SET LOCALDIR=%~f4
SET REMOTEDIR=%5
SET REMOTEFILE=%6

if "%FTPADDRESS%" == "" goto FTP_UPLOAD_USAGE
if "%FTPUSERNAME%" == "" goto FTP_UPLOAD_USAGE
if "%FTPPASSWORD%" == "" goto FTP_UPLOAD_USAGE
if "%LOCALDIR%" == "" goto FTP_UPLOAD_USAGE
if not defined REMOTEDIR goto FTP_UPLOAD_USAGE
if not defined REMOTEFILE goto FTP_UPLOAD_USAGE

:TEMP_NAME
set TMPFILE=%TMP%\%RANDOM%_ftpupload.tmp
if exist "%TMPFILE%" goto TEMP_NAME 

echo user %FTPUSERNAME% %FTPPASSWORD% > %TMPFILE%
echo bin >> %TMPFILE%
echo lcd %LOCALDIR% >> %TMPFILE%

echo cd "%REMOTEDIR%" >> %TMPFILE%
echo mget "%REMOTEFILE%" >> %TMPFILE%
echo quit >> %TMPFILE%

ftp -n -i "-s:%TMPFILE%" %FTPADDRESS%

del %TMPFILE%

goto FTP_UPLOAD_EXIT

:FTP_UPLOAD_USAGE

echo Usage: ftpget [address] [username] [password] [local directory] [remote directory] [remote file pattern]
echo.

:FTP_UPLOAD_EXIT

set FTPADDRESS=
set FTPUSERNAME=
set FTPPASSWORD=
set LOCALDIR=
set REMOTEFILE=
set REMOTEDIR=
set TMPFILE=
set CURRENT_DIRECTORY=
set RELATIVE_DIRECTORY=

@echo on
1 голос
/ 07 августа 2013

У меня была похожая проблема - как и оригинальный постер, я хотел автоматизировать загрузку файлов, но не мог понять, как. Поскольку это находится на регистрационном терминале в магазине моей семьи, я не хотел устанавливать powershell (хотя это выглядит как простой вариант), просто хотел сделать для этого простой файл .bat. Это в значительной степени то, что сказал grawity и другой пользователь; Я новичок в этом, так что вот более подробный пример и объяснение (спасибо также http://www.howtogeek.com/howto/windows/how-to-automate-ftp-uploads-from-the-windows-command-line/, который объясняет, как сделать это только с одним .bat файлом.)

По сути, вам нужно 2 файла - один .bat и один .txt. .Bat сообщает ftp.exe, какие переключатели использовать. .Txt предоставляет список команд для ftp.exe. В текстовом файле поместите это:

username
password
cd whereverYouWantToPutTheFile
lcd whereverTheFileComesFrom
put C:\InventoryExport\inventory.test (or your file path)
bye

Сохраните это где хотите. В файле BAT положить:

ftp.exe -s:C:\Windows\System32\test.txt destinationIP
pause

Очевидно, измените путь после -s: туда, где находится ваш текстовый файл. Уберите паузу, когда вы на самом деле ее запускаете - это просто, чтобы вы могли увидеть любые ошибки. Конечно, вы можете использовать команду «get» или любую другую команду ftp в файле .txt, чтобы делать все, что вам нужно.

Я не уверен, что вам нужна команда lcd в текстовом файле, как я сказал, что я новичок в использовании командной строки для такого типа вещей, но это работает для меня.

0 голосов
/ 25 ноября 2013

Этот скрипт генерирует командный файл, а затем передает командный файл в программу ftp, создавая журнал по пути. Наконец распечатайте оригинальный файл bat, командные файлы и журнал этого сеанса.

@echo on
@echo off > %0.ftp
::== GETmy!dir.bat
>> %0.ftp echo a00002t
>> %0.ftp echo iasdad$2
>> %0.ftp echo help
>> %0.ftp echo prompt
>> %0.ftp echo ascii
>> %0.ftp echo !dir REPORT.CP1C.ROLLEDUP.TXT
>> %0.ftp echo get REPORT.CP1C.ROLLEDUP.TXT
>> %0.ftp echo !dir REPORT.CP1C.ROLLEDUP.TXT
>> %0.ftp echo *************************************************   
>> %0.ftp echo !dir CONTENT.CP1C.ROLLEDUP.TXT
>> %0.ftp echo get CONTENT.CP1C.ROLLEDUP.TXT
>> %0.ftp echo !dir CONTENT.CP1C.ROLLEDUP.TXT
>> %0.ftp echo *************************************************   
>> %0.ftp echo !dir WORKLOAD.CP1c.ROLLEDUP.TXT
>> %0.ftp echo get WORKLOAD.CP1C.ROLLEDUP.TXT
>> %0.ftp echo !dir WORKLOAD.CP1C.ROLLEDUP.TXT
>> %0.ftp echo *************************************************   
>> %0.ftp echo !dir REPORT.TMMC.ROLLEDUP.TXT
>> %0.ftp echo get REPORT.TMMC.ROLLEDUP.TXT
>> %0.ftp echo !dir REPORT.TMMC.ROLLEDUP.TXT
>> %0.ftp echo *************************************************   
>> %0.ftp echo !dir CONTENT.TMMC.ROLLEDUP.TXT
>> %0.ftp echo get CONTENT.TMMC.ROLLEDUP.TXT
>> %0.ftp echo !dir CONTENT.TMMC.ROLLEDUP.TXT
>> %0.ftp echo **************************************************   
>> %0.ftp echo !dir WORKLOAD.TMMC.ROLLEDUP.TXT
>> %0.ftp echo get WORKLOAD.TMMC.ROLLEDUP.TXT
>> %0.ftp echo !dir WORKLOAD.TMMC.ROLLEDUP.TXT
>> %0.ftp echo quit
ftp -d -v -s:%0.ftp 150.45.12.18 > %0.log
type %0.bat 
type %0.ftp 
type %0.log 
0 голосов
/ 28 сентября 2009

У меня была такая же проблема, и я решил ее с помощью решения, аналогичного тому, которое предоставил Cheeso, выше.

"не работает, говорит, что пароль необходим, пробовал пару разными способами"

Да, это потому, что сеансы FTP через командный файл не требуют, чтобы перед именем пользователя стояла строка «пользователь». Брось и попробуй.

Или, возможно, вы видите это, потому что ваш командный файл FTP не закодирован должным образом (это меня тоже укусило). Это дерьмовая часть о генерации командного файла FTP во время выполнения. У внешнего командлета Powershell нет опции кодирования, которую будет принимать Windows FTP (по крайней мере, та, которую я не смог найти).

Независимо от того, как сделать WebClient.DownloadFile это путь.

0 голосов
/ 02 сентября 2009

Попробуйте вручную:

$ ftp www.domainhere.com 
> useridhere
> passwordhere
> put test.txt
> bye
> pause
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...