如何正确转义 bash 脚本中的奇怪字符?

如何正确转义 bash 脚本中的奇怪字符?

我不是脚本编写或查找命令方面的专业人士(只是警告)。我正在尝试创建一个脚本,可以将我的所有 mp3 播客移动到一个文件夹,然后我可以将其移动到我的手机。

所以我制作的脚本需要移动所有 mp3(即使是那些具有奇怪路径的)。我创建了一个脚本,如下所示,它似乎*按照我的意图进行,但它不断给出错误,如下所示:

find /home/jason/gPodder/ -name '*.mp3' -exec bash " cp '{}' /home/jason/gPodder/mp3/ " \;
Which returns:    
bash:  cp '/home/jason/gPodder/Downloads/The Documentary/TheDocumentary20170823-GoingGreenInTheOilState.mp3' /home/jason/gPodder/mp3/ : No such file or directory 

但如果我复制上面的 bash“命令”,它就没有问题。请您帮我理解脚本中的错误是什么。

谢谢

答案1

作为@Kusalananda 说,您缺少-c能够使用内联脚本的功能。

但即便如此,也永远不要将 嵌入{}到 shell 代码中,这将是一个任意命令注入漏洞(例如'$(reboot)'.mp3用您的示例调用的文件)。相反,将其作为内联脚本的参数(假设您确实需要一个内联脚本,并且这cp只是一个示例)。

find ... -exec sh -c 'cp "$1" /home/jason/gPodder/mp3' sh {} \;

(您也不需要bash仅仅为此。您的sh意愿也可以)。

或者更好的是,一次传递多个参数cp

find ... -exec sh -c 'cp "$@" /home/jason/gPodder/mp3' sh {} +

使用 GNU cp,您还可以做到:

find ... -exec cp -t /home/jason/gPodder/mp3 {} +

答案2

不要让它变得比需要的更复杂。

find /home/jason/gPodder/ -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

或者可能

find /home/jason/gPodder/ -type f -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;

只考虑常规文件。

仅当目标文件夹中不存在同名文件时才复制文件,某些cp实现支持-n该选项,或者您可以使用-i重定向自的标准输入/dev/null(但要注意,如果目标类型为目录,则这些不起作用)或者做类似的事情:

find /home/jason/gPodder/ -type f -name '*.mp3' \
    ! -execdir test -e /home/jason/gPodder/mp3/{} \; \
    -exec cp {} /home/jason/gPodder/mp3/ \;

-execdir是 POSIX 标准的扩展find,但受到许多现代find实现的支持。它的执行方式与此类似-exec,但使用找到的内容的父目录作为其工作目录来执行命令。此外,{}将是找到的东西的基本名称(file.mp3或者./file.mp3取决于find实现)而不是它的完整路径。看man find


该错误源于bash "somecommand".bash以这种方式调用时,bash期望somecommand是脚本文件的路径,而不是一系列 shell 命令,并且它无法找到具有您指定名称的脚本。

要执行任意一系列 shell 命令,您需要bash -c "somecommand".

但是,在这种情况下,只需使用-exec cp上面或中的方法即可斯特凡·查泽拉斯的回答

答案3

其他人指出了报价和执行问题。

我建议您不要使用 find -exec,而是查找文件列表,并将该列表通过管道传输到 xargs 和 cp。使用 print0 选项将帮助您避开文件和目录名称中的任何“有趣”字符

例如

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 cp -t destinationpath

这样做的好处是 xargs 将从 find 中收集多个文件名并将它们同时传递给 cp,因此每个 cp 实例可以复制 20 或 100 个文件,而不是为每个文件启动 1 次 cp 调用。 xargs 会为您将足够的文件名放入 cp 命令行中。

您还可以将 -P n 选项添加到 xargs,它将并行启动多个 cp 进程。

前提是您的文件与目标 mp3 文件夹位于同一文件系统上。您可以将 -l 添加到 cp ,它会将文件硬链接到目标,而不是复制它们。

例如

find sourcepath -name \*.mp3 -print0 \
    | xargs -0 -P 5 \
    cp -l -t destinationpath

相关内容