根据文本文件中的列表从一系列目录中复制文件

Copying files from a series of directories based off a list in a text file

我试图在 for 循环中使用 rsynccp 来复制与 [=18= 中新行中存储的 200 个名称列表相匹配的文件] 文件匹配具有 .pdbqt 扩展名的文件名,这些文件名位于具有一个父文件夹的一系列子目录中。 .txt 文件如下所示:

file01
file02
file08
file75
file45
...

我尝试通过以下命令使用 rsync:

rsync -a /home/ubuntu/Project/files/pdbqt/*/*.pdbqt \
--files-from=/home/ubuntu/Project/working/output.txt \
/home/ubuntu/Project/files/top/

当我运行收到rsync命令时:

rsync error: syntax or usage error (code 1) at options.c(2346) [client=3.1.2]

我已经编写了一个 bash 脚本,试图让它工作:

#!/bin/bash
for i in "$(cat /home/ubuntu/Project/working/output.txt | tr '\n' '')"; do
    cp /home/ubuntu/Project/files/pdbqt/*/"$i".pdbqt /home/ubuntu/Project/files/top/;
done

我知道 cat 不是一个很好用的命令,但我想不出替代解决方案,因为我对使用 bash 还是个新手。 运行 我收到以下错误:

tr: when not truncating set1, string2 must be non-empty
cp: cannot stat '/home/ubuntu/Project/files/pdbqt/*/.pdbqt': No such file or directory

我假设 cp 错误是由于 tr 错误而引发的,但我不确定如何摆脱从新行分隔列表中读取的 \n .

预期的结果是 /pdbqt/ 的子目录中包含 12000 个 .pdbqt 文件,output.txt 列表中的 200 个文件将从这些子目录复制到 /top/ 目录.

当您的数据已经在 shell 变量中时,

for 循环很好。从文件中读取数据时,while ... read 循环效果更好。在你的情况下,尝试:

while IFS= read -r file; do  cp -i -- /home/ubuntu/Project/files/pdbqt/*/"$file".pdbqt  /home/ubuntu/Project/files/top/; done </home/ubuntu/Project/working/output.txt

或者,如果您发现多行版本更具可读性:

while IFS= read -r file
do
    cp -i -- /home/ubuntu/Project/files/pdbqt/*/"$file".pdbqt /home/ubuntu/Project/files/top/
done </home/ubuntu/Project/working/output.txt

工作原理

  • while IFS= read -r file; do

    这会启动一个 while 循环,一次读取一行。 IFS= 告诉 bash 不要从行中截断白色 space 并且 -r 告诉 read 不要破坏反斜杠。该行存储在名为 file.

  • 的 shell 变量中
  • cp -i -- /home/ubuntu/Project/files/pdbqt/*/"$file".pdbqt /home/ubuntu/Project/files/top/

    这将复制文件。 -i 告诉 cp 在覆盖现有文件之前询问。

  • done </home/ubuntu/Project/working/output.txt

    这标志着 while 循环的结束,并告诉 shell 从 /home/ubuntu/Project/working/output.txt

  • 获取循环的输入

Project/files/pdbqt/* 中的目录或文件 *.pdbqt 的名称中是否包含破折号 (-)?

错误显示 rsync 源代码中的行 options.c "Your options have been rejected by the server.\n"

这让我认为它正在将您的 glob 中的 inode (files/dirs) 解释为 rsync 选项。

for i in $( < /home/ubuntu/Project/working/output.txt LC_CTYPE=C tr '\n' ' ' )
do
  cp /home/ubuntu/Project/files/pdbqt/*/"${i}.pdbqt" /home/ubuntu/Project/files/top/
done

我认为你的 cat tr 缺少 space

cat /home/ubuntu/Project/working/output.txt | tr '\n' ' '

whileread的使用比我的好。

你的想法是正确的rsyncrsync 提供选项 --files-from="yourfile",它将 rsynctextfile 中的所有文件(相对于您接下来指定的基本目录)到目的地(host:/dest/path或在本地单独使用 /dest/path)

您需要指定 --no-R 来告诉 rsync 不要使用相对文件名,因为 --files-from= 将基本路径作为下一个参数。例如,要将文本文件中的所有文件传输到指定文件位置在当前目录中的某个远程主机,您可以使用:

rsync -uai --no-R --files-from="textfile" ./ host:/dest/path

命令基本上指定您从 textfile 读取要传输的名称,文件将在 ./(当前目录)下找到,然后您将文件传输到 host:/dest/path 在您指定的 host 上。您可以查看 man 1 rsync 了解完整详情。