使用 WinSCP 从 SFTP 服务器下载超过 X 天的文件,跳过不包含任何匹配文件的文件夹

问题描述:

我仅限于 PuTTY 和 WinSCP.

I am limited to PuTTY and WinSCP only.

我正在尝试下载带有日志文件的日志目录.例如,我想获取 6 天前或更新后的所有 log_files.log_dir2log_dir3 包括文件夹符合条件,而 log_dir1 及其文件不符合条件.

I am trying to download log directories with log files. For example, I want to grab all log_files 6 days old or newer. log_dir2 and log_dir3 including the folders match the criteria, while log_dir1 and its files does not.

DIR/log_dir1/log_files % older than 6 days
DIR/log_dir2/log_files % meets criteria
DIR/log_dir3/log_files % meets criteria

我的问题是,虽然没有下载 log_dir1log_files,但我目前使用的语法会下载 log_dir1 文件夹.通常情况下,没什么大不了的,但我们正在讨论数百个 log_dir 文件夹(所有文件都是空的,因为文件超过 6 天).由于我无法控制的原因,我无法移动或归档这些旧日志目录及其日志文件.

My problem is that while the log_files of log_dir1 are not downloaded, the syntax I am currently using downloads the log_dir1 folder. Normally, not a big deal, but we are talking hundreds of log_dir folders (all empty as the files are older than 6 days). For reasons beyond my control, I cannot move or archive these old log directories with their log files.

我的问题很简单,如何更改语法以忽略早于 6 天的文件夹和文件.

My question is simply, how do I change my syntax to ignore folders that are older than 6 days as well as files.

get -filemask="*>6D" /DIR/* C:\temp

我尝试了几种不同的参数组合,并阅读了有关目录掩码和路径掩码的支持页面.我无法让它们中的任何一个工作(版本问题?).谁能比帮助页面更好地解释他们的语法.我明天会更新我正在使用的 WinSCP 的当前版本.

I have tried several different combinations of parameters and I have read the support page about Directory Masks and Path Masks. I cannot get any of them working (version issue?). Can anyone explain their syntax better than the help page. I will update tomorrow with the current version of WinSCP that I am using.

WinSCP 文件中的时间限制掩码不能用于目录.

但您可以阻止 WinSCP 创建空文件夹.使用 -rawtransfersettings 开关ExcludeEmptyDirectories 设置.

But you can prevent WinSCP from creating the empty folders. Use -rawtransfersettings switch with ExcludeEmptyDirectories setting.

get -rawtransfersettings ExcludeEmptyDirectories=1 -filemask="*>6D" /DIR/* C:\temp


这是原始答案,在 WinSCP 支持 ExcludeEmptyDirectories 之前.对于具有更具体约束的实现,它可能仍然有用.


This is the original answer, before WinSCP supported ExcludeEmptyDirectories. It might still be useful as a basis for implementations that have even more specific constraints.

您可以在 PowerShell 脚本中使用 WinSCP .NET 程序集轻松实现此自定义逻辑:

# Load WinSCP .NET assembly
Add-Type -Path "WinSCPnet.dll"

# Set up session options
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
    Protocol = [WinSCP.Protocol]::Sftp
    HostName = "example.com"
    UserName = "username"
    Password = "password"
    SshHostKeyFingerprint = "..."
}

$remotePath = "/remote/path"
$localPath = "C:\local\path"
$limit = (Get-Date).AddDays(-6)

$session = New-Object WinSCP.Session

# Connect
$session.Open($sessionOptions)

# Enumerate files to download
$fileInfos =
    $session.EnumerateRemoteFiles(
        $remotePath, $Null, [WinSCP.EnumerationOptions]::AllDirectories) |
    Where-Object { $_.LastWriteTime -gt $limit }

foreach ($fileInfo in $fileInfos)
{
    $localFilePath =
        [WinSCP.RemotePath]::TranslateRemotePathToLocal(
            $fileInfo.FullName, $remotePath, $localPath)

    # If the corresponding local folder does not exist yet, create it
    $localFileDir = Split-Path -Parent $localFilePath
    if (!(Test-Path -Path $localFileDir))
    {
        Write-Host "Creating local directory $localFileDir..."
        New-Item $localFileDir -ItemType directory | Out-Null
    }

    Write-Host "Downloading file $($fileInfo.FullName)..."

    # Download file
    $sourcePath = [WinSCP.RemotePath]::EscapeFileMask($fileInfo.FullName)
    $transferResult = $session.GetFiles($sourcePath, $localFilePath)

    # Did the download succeeded?
    if (!$transferResult.IsSuccess)
    {
        # Print error (but continue with other files)
        Write-Host ("Error downloading file ${remoteFilePath}: " +
            $transferResult.Failures[0].Message)
    }
}

$session.Dispose()

Write-Host "Done."

像这样运行脚本(download.ps1):

powershell.exe -ExecutionPolicy Unrestricted -File download.ps1