command-line - script - ftp via shell
¿Cómo se programa la carga y descarga de FTP? (9)
Estoy intentando hacer un archivo por lotes para cargar un archivo al servidor ftp. Si lo escribo manualmente, funciona bien, pero cuando ejecuto el archivo por lotes, se detiene después de que está conectado ... dice
connected to domain.com.
220 microsoft ftp server
User(domain.com:(none)):
entonces nada más. ¿Qué diablos está pasando aquí?
Debajo está mi archivo por lotes:
ftp www.domainhere.com
user useridhere
passwordhere
put test.txt
bye
pause
Crea un archivo de comando con tus comandos
es decir: comandos.txt
open www.domainhere.com
user useridhere
passwordhere
put test.txt
bye
A continuación, ejecute el cliente FTP desde la línea de comando: ftp -s: commands.txt
Nota: Esto funcionará para el cliente FTP de Windows.
Editar: debería haber tenido un salto de línea después del nombre de usuario antes de la contraseña.
Es una idea razonable querer crear secuencias de comandos de una sesión de FTP de la forma en que el cartel original se imaginó, y ese es el tipo de cosas en las que esperaría ayuda. Los archivos por lotes en Windows no pueden hacer esto.
Pero en lugar de ejecutar cURL o Expect, puede que le resulte más fácil realizar un script de la interacción de FTP con Powershell. Es un modelo diferente, ya que no está escribiendo directamente el texto para enviarlo al servidor FTP. En cambio, utilizará Powershell para manipular objetos que generen el diálogo FTP para usted.
Subir:
$File = "D:/Dev/somefilename.zip"
$ftp = "ftp://username:[email protected]/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)
Descargar:
$File = "c:/store/somefilename.zip"
$ftp = "ftp://username:[email protected]/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)
Necesitas Powershell para hacer esto. Si no lo sabe, Powershell es un shell como cmd.exe que ejecuta sus archivos .bat. Pero Powershell ejecuta archivos .ps1 y es bastante más potente. Powershell es un complemento gratuito para Windows y se incorporará a futuras versiones de Windows. Consíguelo aquí .
Fuente: http://poshcode.org/1134
Estaba teniendo un problema similar: al igual que el póster original, quería automatizar la carga de un archivo, pero no pude entender cómo. Como esto está en una terminal de registro en la tienda de mi familia, no quería instalar PowerShell (aunque parece una opción fácil), solo quería un archivo .bat simple para hacer esto. Esto es más o menos lo que dijo grawity y otro usuario; Soy nuevo en esto, así que aquí hay un ejemplo y una explicación más detallados (gracias también a http://www.howtogeek.com/howto/windows/how-to-automate-ftp-uploads-from-the-windows-command-line/ quién explica cómo hacerlo con solo un archivo .bat.)
Esencialmente necesitas 2 archivos: uno .bat y uno .txt. El .bat le dice a ftp.exe qué cambios usar. El archivo .txt proporciona una lista de comandos para ftp.exe. En el archivo de texto, coloca esto:
username
password
cd whereverYouWantToPutTheFile
lcd whereverTheFileComesFrom
put C:/InventoryExport/inventory.test (or your file path)
bye
Guarde eso donde quiera. En el archivo BAT pon:
ftp.exe -s:C:/Windows/System32/test.txt destinationIP
pause
Obviamente, cambie la ruta después de -s: donde sea que esté su archivo de texto. Elimina la pausa cuando la ejecutas, solo para que puedas ver los errores. Por supuesto, puede usar "get" o cualquier otro comando ftp en el archivo .txt para hacer lo que necesite hacer.
No estoy seguro de que necesite el comando lcd en el archivo de texto, como dije que soy nuevo en el uso de la línea de comandos para este tipo de cosas, pero esto está funcionando para mí.
Este script genera el archivo de comando y luego canaliza el archivo de comando al programa ftp, creando un registro a lo largo del camino. Finalmente, imprima el archivo bat original, los archivos de comando y el registro de esta sesión.
@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
He hecho esto con 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
Los archivos por lotes no funcionan de esa manera. No solo "escriben" todo: ejecutan comandos del sistema, en este caso ftp
, esperan a que vuelvan, y ejecutan el siguiente comando ... entonces, en este caso, el intérprete simplemente está esperando que ftp
salga.
Si debe usar el comando ftp
, prepare un archivo de script (por ejemplo, commands.txt
y ejecute ftp -s:commands.txt
.
Pero usar cURL , o un script PHP / Perl / Python / lo que sea, puede ser una mejor idea.
Pruebe de forma manual:
$ ftp www.domainhere.com
> useridhere
> passwordhere
> put test.txt
> bye
> pause
Sé que esta es una vieja pregunta, pero quería agregar algo a las respuestas que ya están aquí con la esperanza de ayudar a alguien más.
Puede ftp
comando ftp
con la opción -s:filename
. La sintaxis es solo una lista de comandos para pasar al shell ftp
, cada uno terminado por una nueva línea. Esta página tiene una buena referencia a los comandos que se pueden realizar con ftp
.
Cargar / Descargar toda la estructura del directorio
Usar el ftp
normal no funciona muy bien cuando necesita tener un árbol de directorios completo copiado ao desde un sitio ftp. Entonces podrías usar algo como esto para manejar esas situaciones.
Estos scripts funcionan con el comando ftp
Windows y permiten cargar y descargar directorios completos desde un solo comando. Esto lo hace bastante autosuficiente cuando se usa en diferentes sistemas.
Básicamente lo que hacen es mapear la estructura del directorio que se va a subir / descargar, volcar los comandos ftp
correspondientes a un archivo, luego ejecutar esos comandos cuando la asignación ha terminado.
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
Tuve el mismo problema y lo resolví con una solución similar a la que proporcionó Cheeso anteriormente.
"no funciona, dice que la contraseña es necesaria, lo intenté de dos maneras diferentes"
Sí, eso es porque las sesiones de FTP a través de un archivo de comandos no requieren que el nombre de usuario tenga el prefijo "usuario". Suelta eso y pruébalo.
O bien, podría estar viendo esto porque su archivo de comando FTP no está codificado correctamente (eso también me mordió). Esa es la parte mala de generar un archivo de comando FTP en tiempo de ejecución. El cmdlet out-file de Powershell no tiene una opción de codificación que acepte el FTP de Windows (al menos no uno que yo pueda encontrar).
De todos modos, como hacer un WebClient.DownloadFile es el camino a seguir.