使用 exec sh 的 find 命令在 shell 脚本中不起作用,但在命令行中起作用(raspberrypi)

使用 exec sh 的 find 命令在 shell 脚本中不起作用,但在命令行中起作用(raspberrypi)

我想找到“旧”文件夹/volume1/photo/ipcam这些文件被命名为“????-??-??”,并将 dropbox 中的相应文件夹(具有相同的目录结构 /ipcam/...)移动到子文件夹/ipcam/存档下面的 find 命令(使用适当的值代替变量)在命令行中使用时可以正常工作,但在脚本中使用时则不行:

通过命令行:

find /volume1/photo/ipcam -maxdepth 1 -type d -name "????-??-??" -mtime +0 -exec sh -c 'echo /home/pi/Dropbox-Uploader/dropbox_uploader.sh move /ipcam/$(basename {}) /ipcam/archive' \;

通过脚本:

#!/bin/bash    
path2disc="/volume1"
source="$path2disc/photo/ipcam"

dropboxtool="/home/pi/Dropbox-Uploader/dropbox_uploader.sh"
dropbox="/ipcam"
dropboxarchive="/ipcam/archive"

find $source -maxdepth 1 -type d -name "????-??-??" -mtime +0 -exec sh -c '$dropboxtool move $dropbox/$(basename {}) $dropboxarchive' \;

我认为“脚本”版本中的引号有问题,但不确定。

PS:在raspberrypi上使用以下版本: Linux raspberrypi 3.10.24+ #614 PREEMPT 星期四 十二月 19 20:38:42 GMT 2013 armv6l GNU/Linux

答案1

我认为“脚本”版本中的引号有问题,但不确定。

是的,有些地方不对:单引号内的变量不会被替换。在某些情况下,只需将单引号改为双引号即可。不是正确的事情尽管。

在评论中您说-exec sh -c "$dropboxtool move $dropbox/$(basename {}) $dropboxarchive" \;有效。但这段代码仍然有严重缺陷。

问题:

  1. 永不嵌入{}shell 代码!这会产生命令注入漏洞。find机械地替换{}然后sh -c解释结果(以及其余参数),可能是代码。

  2. 类似地,如果你让当前 shell 替换嵌入在 shell 代码中的变量,那么sh -c结果可能会被解释为代码。带有;>或等字符的变量|可能会完全改变即将执行的内容。你不应该这样做,除非:

    • 从变量注入代码是你明确想要的;
    • 或者您绝对确定扩展的变量是安全的,但即便如此,这也不是一个好的做法。
  3. 引用应该引用的内容:

    • $source(就find在你的原始代码之后)应该用双引号引起来
    • 引用有两种级别。一般来说,某些字符串应该被引用在调用的 shell 上下文中find。这意味着到达的选项参数sh -c(在外壳删除外部引号之后)应该包含一些引号,否则在某些情况下代码将会中断。

您的代码应该看起来更像这样:

find "$source" -maxdepth 1 -type d -name "????-??-??" -mtime +0 -exec sh -c \
   '"$1" move "$2/$(basename "$4")" "$3"' \
   find-sh "$dropboxtool" "$dropbox" "$dropboxarchive" {} \;

这里$1,,,和不会被当前 shell 扩展,因为它们是单引号$2$3$4$( )外部引号很重要)。整个单引号字符串到达sh -c​​,然后这些标记才会被扩展。请注意,它们在此级别被正确双引号括起来。当前 shell 或 by 需要替换的所有内容都会find作为位置参数传递给内壳find-sh(解释这里),代码本身是静态的。

相关内容