将查找结果存储在变量中然后传递给 cp?

将查找结果存储在变量中然后传递给 cp?

我需要根据经过的时间处理一组文件(因为我无法控制何时将新文件添加到远程目录)。

我必须对这组文件执行多项操作,因此我尝试将find结果存储在变量中(这样我可以确保经过的候选者不会更改),然后find对每个操作使用相同的列表(无需再次执行)。

这是我正在尝试的精简版本。

FILELIST=$(ssh ${SSHUSER}@${SSHHOST} "cd ${REMOTEPATH}; find -amin +${TIME} -type f,d -print")

if [[ ${#FILELIST} -lt 4 ]]; then
  echo "No files" >> ${LOGFILE}
  exit 1
fi

echo -en "Copying remote files to remote backup\n" >> ${LOGFILE}
ssh ${SSHUSER}@${SSHHOST} "cd ${REMOTEPATH}; cp -Rpv '${FILELIST}' ${REMOTEBACKUPPATH}" >> ${LOGFILE}

这当然给了我cp: missing destination file operand after ''我所理解的。我只是不知道如何以cp喜欢的方式格式化文件列表。

我已经为此工作了一段时间,阅读文档/SE 帖子,但无法弄清楚。我希望一旦我知道自己做错了什么,cp我也可以将这些知识应用到rsync.

我是 bash 脚本领域的新​​手,如果这还不清楚的话。 :)

提前致谢。

答案1

bash不是处理这个问题的最佳外壳。我建议zsh改为(您已经zsh通过不引用某些参数扩展来使用语法):

filelist=(
  ${(0)"$(
    ssh $SSHUSER@$SSHHOST "
      cd -- ${(qq)REMOTEPATH} &&
        find . -amin +${TIME} -type f,d -prune -print0"
  )"}
)

if (( $#filelist < 4 )); then
  print No files >> $LOGFILE
else
  print "Copying remote files to remote backup" >> $LOGFILE
  print -rNC1 -- $filelist | ssh $SSHUSER@$SSHHOST "
    cd -- ${(qq)REMOTEPATH} && xargs -r0 cp -Rpvt ${(qq)REMOTEBACKUPPATH}"
fi

(假设$SSHHOST是一个 GNU 系统(你自己已经使用了一些 GNUisms,比如f,d,没有文件传递到find, cp -v),并且那里的登录 shell$SSHUSER是类似 Bourne 的)。

我已-prunefind命令中添加了内容,因为您将以任何方式复制这些整个目录,因此无论如何都没有必要在其中查找更多文件。读取这些目录的内容也会更新它们的上次访问时间。

无论如何,请注意,读取目录中的文件不会更新目录的访问时间。当读取目录自身的内容时,目录的访问时间会更新,就像您在目录中使用ls/find或 shell 全局变量时一样(另请注意,如今,访问时间并不总是得到彻底维护)。所以不清楚你到底想做什么。

上面我们使用:

  • filelist=( values )定义一个大批变量(其中filelist=value定义一个标量变量代替)。
  • ${(0)"$(cmd)"}cmd分割NUL 上的输出。使用 NUL 分隔列表是传递文件路径列表的安全方法,因为 NUL 是文件路径中唯一不允许的字符。
  • cd -- ${(qq)REMOTEPATH}, with--来防止$REMOTEPATH以 开头的值-(不是-它本身,但在某些 shell 中也不是-4/ +3),以及引用的值$REMOTEPATH(在此处由本地 shell 扩展)(使用单引号与qq,唯一安全的方法$REMOTEPATH)对于远程 shell(假设它是类似 Bourne 的,如果登录 shell 是csh/fish/rc... ,则对于某些值不起作用$SSHUSER)。
  • 请注意,&&它确保仅在cd成功时才运行下一个命令,否则您将在错误的目录中运行它。
  • -print0:打印 NUL 分隔的文件路径(见上文)。
  • 然后$#filelist将包含匹配文件的数量(我们将其与原始代码中的 4 个进行比较,不知道为什么)。
  • 然后我们需要将该列表发送回远程主机。我们不是将其作为为远程 shell 发送的 shell 代码中的参数传递(为此我们会遇到各种问题和限制),而是在 stdinprint -N上将其以 NUL 分隔(用 )传递ssh,这是继承的在xargs那儿。
  • xargs读取该列表并将其转换为参数cp -t target-t也是 GNU 扩展)。xargs将根据需要运行尽可能多的cps 以避免参数大小限制。

相关内容