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

Spo*_*pot 0 find cp shell-script

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

我必须对这组文件进行多次操作,因此我试图将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}
Run Code Online (Sandbox Code Playgroud)

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

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

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

提前致谢。

Sté*_*las 5

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
Run Code Online (Sandbox Code Playgroud)

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

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

在任何情况下,请注意读取目录中的文件不会更新目录的访问时间。目录的访问时间在读取它自己的内容时更新,就像您在其中使用ls/find或 shell glob一样(另请注意,如今,访问时间并不总是得到彻底维护)。所以目前还不清楚你到底想做什么。

以上我们使用:

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