【问题标题】:Using (scp | rsync) to pull specific files while creating folder structure at same time?使用 (scp | rsync) 在创建文件夹结构的同时提取特定文件?
【发布时间】:2019-10-08 05:14:29
【问题描述】:

我有一个托管在服务器上的大型项目,其中包含我想要复制到本地计算机的相同文件夹结构中的特定文件,但只有我想要的特定文件。我当前查找这些文件的命令是(在服务器上的项目中):

find ./ -type f -name '*_out.csv' ! -path './*/doc/*' 2>/dev/null

生成这样的列表(为简洁起见被截断):

./validation/Riso_AN8/analysis/Riso_AN8_out.csv
./validation/FUMEXII_Regate/analysis/Regate_smeared_out.csv
./validation/FUMEXII_Regate/analysis/Regate_discrete_out.csv
./validation/IFA_432/analysis/rod3/IFA_432_rod3_out.csv
./validation/IFA_432/analysis/rod1/IFA_432_rod1_out.csv
./validation/IFA_432/analysis/rod2/IFA_432_rod2_out.csv
./validation/LOCA_REBEKA_cladding_burst_tests/analysis/rebeka_2d_06MPa/rebeka_singlerod_2d_06MPa_out.csv
./validation/LOCA_REBEKA_cladding_burst_tests/analysis/rebeka_2d_06MPa/rebeka_singlerod_2d_06MPa_tm_out.csv
./validation/LOCA_REBEKA_cladding_burst_tests/analysis/rebeka_2d_08MPa/rebeka_singlerod_2d_08MPa_tm_out.csv

我想使用scprsync 将这些文件拉到我的本地计算机并创建文件夹结构,其中不包含任何其他内容。解决此问题的最佳方法是什么?我有 的文件,所以我真的不想事先创建文件夹结构。我也无法从服务器中提取整个项目,因为它很大,系统管理员会生我的气。

有没有办法拉取这些文件,同时在我的本地机器上创建文件夹结构?

【问题讨论】:

  • 使用dirname 提取路径名的目录部分,并使用mkdir -p 创建本地目录结构。然后使用rsyncscp 将文件复制到该目录。
  • 我认为您可以只使用 rsync-include-exclude 选项来复制您想要的文件。

标签: bash unix rsync scp


【解决方案1】:

我认为您可以使用rsync--exclude--include 选项来做到这一点。

rsync --recursive --include '*_out.csv' --exclude '*/doc/*' server:path/to/remote/dir path/to/local/dir

【讨论】:

  • 我通常会这样做。我唯一不清楚的是,如果路径的初始部分不存在(例如开始在本地机器上有一个空目录并尝试rsync -uav /path/to/file/with/several/dirs/to/file.txt。在这种情况下,您需要在rsync 调用之前在本地创建/path/to/file/with/several/dirs/to 的一部分。
  • rsync 将自动创建任何需要的中间目录。
  • 除非中间路径不存在并且您正在按名称复制单个文件,例如(rsync -uav valkyrie:/home/david/tmp/ttt/CMakeFiles/TicTacToe.dir/link.txt ttt/CMakeFiles/TicTacToe.dir/) 如果本地不存在ttt/CMakeFiles/TicTacToe.dir/,则结果为rsync: mkdir "/home/david/tmp/ttt/CMakeFiles/TicTacToe.dir" failed: No such file or directory (2)
  • 但我不会按名称复制单个文件。我正在使用--recursive 选项复制整个目录层次结构,但将其过滤到他想要的文件。
  • 是的,我知道,这只是我在问题中看到的区别,如果我将问题解释错了,我会感到困惑。我用它来引出所有*_out.csv 文件,这些文件可能分散在提问者正在查看的基本目录下的所有地方。
【解决方案2】:

我会鼓励rsync,我可能会通过ssh 调用find,使用basedir进程替换中提取文件。然后,您可以提供while 循环以读取在服务器上找到的每个文件名,获取路径并使用mkdir -p 在当前目录下的本地计算机上创建路径(带有验证)。然后您可以调用rsync 以使用rsync -uav 将文件从服务器拉到正确的目录。例如,您可以执行类似的操作:

#!/bin/bash

server=${1:-yourserver}       ## your server name
basedir=${2:-/path/to/files}  ## the base directory to run find on server

while read -r line; do        ## read line at a time from find output on server
    dname="${line%/*}"        ## separate directory name
    mkdir -p "$dname" || {    ## create/validate directory from remote file
        printf "error: unable to create '%s'.\n", "$dname" >&2
        continue
    }
    rsync -uav "$server:$line" "$dname" ## rsync file to correct directory
done < <(ssh "$server" "find $basedir -type f -name '*_out.csv' ! -path './*/doc/*' 2>/dev/null")

然后只需调用本地机器上的脚本,提供服务器名称作为第一个参数和文件在服务器上的基本目录。确保将本地计算机上的目录更改为要在其下创建远程目录结构的目录。这假定您的 find 调用(由本地计算机上的 ssh 在服务器上执行)返回您希望复制到本地计算机的文件列表。

这并不像单个 rsync 调用那样有效,但是如果您的 find 命令在远程目录树下生成分支,这些分支在文件名之前具有多级目录,否则不会在本地创建机器,您必须手动确保在远程文件上调用 rsync 之前创建这些路径。

【讨论】:

  • 是你的最后一句话:你的意思是我在我的脚本中定义了一些东西,比如line=($(ssh -qn user@server "find /path/to/files -type f -name '*_out.csv' -not -path '*/doc/*' 2&gt;/dev/null")),这就是我将使用 while 循环迭代的内容?
  • 是的。请参阅我添加的最后一段。如果您只是复制整个目录,那么您只需要一个 rsync 电话(正如 Barmar 在他的回答中所示)。但是,如果您从远程机器上的嵌套目录结构中复制分散的文件,那么您将需要遍历文件(如上)并手动创建要复制到的路径 --- rsync 通常不会创建嵌套复制文件的目录(如果您要复制整个基本目录,则会这样做)。
  • 谢谢,这对我帮助很大。另一个答案似乎可行,但它最终复制了所有内容,而不仅仅是*_out.csv 文件。你有资源可以指点我&lt; &lt; 语法吗?我从来没有在 bash 中看到过这个,我很好奇将来如何使用它。
  • 当然,这只是一个名为 进程替换 的 bash 功能。 Process Substitution (Bash Reference Manual) 您重定向进程替换的输出以提供while 循环,就像重定向文件一样。对于文件,您将使用&lt; file,而对于进程替换,您将使用&lt; &lt;(process)。对于进程替换&lt; &lt; 之间必须有一个空格
猜你喜欢
  • 2013-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-14
  • 1970-01-01
  • 2021-05-16
  • 2014-05-28
相关资源
最近更新 更多