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

Jas*_*mit 5 scripting bash find special-characters

我在脚本或查找命令方面并不专业(只是一个警告)。我正在尝试创建一个脚本,该脚本可以将我所有的 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 
Run Code Online (Sandbox Code Playgroud)

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

谢谢

Sté*_*las 7

正如@Kusalananda 所说,您缺少一个-c能够使用内联脚本的方法。

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

find ... -exec sh -c 'cp "$1" /home/jason/gPodder/mp3' sh {} \;
Run Code Online (Sandbox Code Playgroud)

(您也不仅仅需要这样做bash。您sh也可以这样做)。

或者更好的是,一次将几个参数传递给cp

find ... -exec sh -c 'cp "$@" /home/jason/gPodder/mp3' sh {} +
Run Code Online (Sandbox Code Playgroud)

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

find ... -exec cp -t /home/jason/gPodder/mp3 {} +
Run Code Online (Sandbox Code Playgroud)


Kus*_*nda 6

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

find /home/jason/gPodder/ -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;
Run Code Online (Sandbox Code Playgroud)

或者可能

find /home/jason/gPodder/ -type f -name '*.mp3' -exec cp {} /home/jason/gPodder/mp3/ \;
Run Code Online (Sandbox Code Playgroud)

只考虑常规文件。

如果目标文件夹中不存在同名文件,则仅复制文件,某些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/ \;
Run Code Online (Sandbox Code Playgroud)

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


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

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

但是,在这种情况下,只需使用-exec cp如上或Stéphane Chazelas 的回答