通过 ssh 将通配符文件从 Linux 移动到 Windows

通过 ssh 将通配符文件从 Linux 移动到 Windows

如果这个问题已经存在,请原谅我,但我找不到一个完全一样的问题:

我们目前有一个 Linux 系统,它可以生成*.dat文件并直接保存在服务器上。然后,我们在单独的 Windows 服务器上运行一个脚本,该脚本使用 psftp 连接到服务器,使用以下命令复制它们并删除它们:

mget *.dat
del *.dat

然而,问题是我们发现文件丢失并完全消失。也许文件是在 mget 和 del 命令运行之间的时间内生成的 - 导致文件在被复制之前就被删除。

我很高兴找到任何解决方案,但不确定如何最好地编写此脚本:

  • 仅删除已明确复制的文件
  • 复制文件后将其移动到 Linux 服务器上的存档目录,以免再次复制。

我尝试过使用mv,但显然这不适用于通配符表达式。因此,我认为我需要先使用mls或类似方法生成要移动/复制的文件列表,然后使用循环运行命令 - 但不完全确定如何将其放入在任务计划程序中运行的脚本中。

任何想法都值得感激。谢谢。

答案1

mv如果使用得当,使用通配符应该可以起作用。

但是使用mv *.dat …将文件移动到另一个远程目录被抄袭和你原来的方法一样有缺陷。

移动文件第一的。目标目录将成为您的文件列表。从中获取文件。

mkdir transfer
mv *.dat transfer/
mget transfer/*.dat
del transfer/*.dat
rmdir transfer

请注意,这个简单的代码片段仍然很愚蠢,命令可能会失败,所以不要让代码在出错时继续运行(不要使用pstfp -be …)。特别是如果mget失败而代码继续运行,del将导致数据丢失。尽管如此,在两者之间生成的文件的问题已经解决:在和之间mget没有del添加到transfer目录中。

还有一个问题。无论哪个进程.dat在服务器上生成文件,它都应该写入不匹配的临时文件*.dat,完成写入,然后原子地将文件移动到最终路径名。否则mvmgetdel可能会在不完整文件(在 Linux 中,您可以移动或删除打开并正在写入的文件)。希望该过程足够智能,能够以这种方式工作。如果它不够智能,这个问题就不容易解决。如果它足够智能,那么文件的存在.dat就意味着文件是完整的。

答案2

有些细节遗漏了,但我会做出假设。具体来说,这个过程是由我假设的批处理文件驱动的,看起来像这样...

@echo off
psftp user@host -b mypsftpcmds.dat

并且 mypsftpcmds.dat 当然会有您在问题中提供的命令......

mget *.dat
del *.dat

我认为有几种方法可以使它更强大。我想到的一个简单解决方案是仅删除 Linux 主机上您确定存在于 Windows 主机上的文件。为此,我将单独执行“mget *.dat”,然后在批处理文件中对 Windows 目录中找到的每个 *.dat 文件运行“psftp del”。

在下面的示例中,我创建了一个临时文件,其中包含在 Windows 主机上找到的每个 *.dat 文件的 psftp 删除命令。然后使用该临时文件调用“psftp -b”。

例如,您的批处理文件可能看起来像......

@echo off
psftp user@host -b mgetCommandOnly.dat
FOR %%F IN (*.dat) DO (
    echo del %%F > tmpfile.dat
    psftp user@host -b tmpfile.dat
)
del tmpfile.dat

并且您的第一个 psftp 命令文件(我的示例中为“mgetCommandOnly.dat”)只有一行......

mget *.dat

此解决方案可能需要进一步调整。例如,如果您始终复制到同一个 Windows 目录中,那么前几天的旧 *.dat 文件可能仍然存在。“FOR %%F”命令也会处理这些文件,这意味着它将尝试从 Linux 主机中删除同名文件。

例如,假设周一 Linux 包含三个 *.dat 文件

aaa.dat
bbb.dat
ccc.dat

.. 并且您的批处理成功将这些文件拉到 Windows 并从 Linux 中删除它们。但如果星期二 Linux 只有两个 *.dat 文件...

aaa.dat
bbb.dat

.. 您的批处理文件将毫无问题地抓取这两个文件。但是从星期一开始 ccc.dat 仍然存在于 Windows 上!这意味着“FOR %%F”循环将尝试删除 aaa.dat、bbb.dat(成功)和 ccc.dat(失败)。它在 ccc.dat 上失败,因为星期二 ccc.dat 从未存在于 Linux 主机上。

这会导致出现文件不存在的错误消息,但我认为这不会导致批处理文件中止。如果您愿意忽略此​​类错误消息,则无需担心使批处理文件在这方面更加智能。

但是,如果您想避免这种情况,您可能需要(如果这是一个可接受的解决方案)在运行 mget 命令之前从 Windows 目录中删除所有旧的 *.dat 文件。或者至少备份旧的 *.dat 文件并将它们存储在其他地方。

此外,我的解决方案不能保证复制的文件与原始文件完全相同。理论上它们可能会损坏。不太可能,但如果您真的想保证复制准确,我的解决方案无法解决这个问题。如果您需要这方面的建议,请告诉我,我会发布一种方法来做到这一点。或者,如果您自己尝试,请注意您是以二进制模式还是文本模式传输文件。如果是后者,文件大小很可能会有所不同,因为 Linux 行尾(换行符)将在 Windows 端被替换为回车符/换行符(CR/LF)对。

另一个稍微复杂一些的解决方案是先运行 psftp dir 命令,将结果保存到本地临时文件,然后对临时文件中找到的每个文件执行单独的获取和删除操作。这可能比我原来的解决方案更强大、更精确。如果您有兴趣,我可以建议您这样做。

最后...至于在原始解决方案中运行 mget *.dat 和 del *.dat 之间是否创建了文件,取决于文件的数量和文件的大小,mget *.dat 和 del *.dat 命令可能相隔很长的一段时间,并且两个命令之间可能会出现新文件。这将导致 del *.dat 删除更多的文件比 mget *.dat 检索到的要多 - 这很可能就是您所遇到的问题。

上述解决方案不会删除 Linux 上任何尚未复制到 Windows 的文件。这是我的解决方案最重要的优点。

我的解决方案没有解决的问题是您是否要提取在 mget *.dat 之后和批处理文件结束之前出现的任何新的 *.dat 文件。

一个简单的方法是连续运行两次脚本。任何新的 *.dat 文件都会在第二次调用时被拾取。

相关内容