Bash 复制所有与给定扩展名不匹配的文件

Ada*_*dam 8 bash file-copy wildcards

当我从 Shotwell 中的相机导入图片时,它也会导入视频剪辑。这有点烦人,因为我想将我的视频存储在另一个文件夹中。我尝试编写一个 bash 命令来执行此操作,但没有成功。

我需要一个满足以下要求的命令:

  • 找到目录结构中没有 .jpg、.png、.gif 或 .xcf(不区分大小写)扩展名的所有文件。
  • 将所有这些文件移动到目标目录中,无论文件名或目录路径是否包含空格或特殊字符。

任何帮助,将不胜感激!

编辑:我在 Ubuntu 中使用默认 shell,这意味着某些命令是别名等。

编辑 2:我自己尝试过(不是复制部分,只是文件列表部分)。我打开 extglob 并运行以下命令:

$ ls -R /path | awk '
  /:$/&&f{s=$0;f=0}
  /:$/&&!f{sub(/:$/,"");s=$0;f=1;next}
  NF&&f{ print s"/"$0 }'
Run Code Online (Sandbox Code Playgroud)

这列出了一切。我尝试在它的末尾使用 grep,但对于如何让它不匹配我给它的模式没有最模糊的想法。extglob 开关对 grep 没有太大帮助,即使它对其他命令有帮助。

Mic*_*mer 14

您可以使用find在目录树中查找匹配(或不匹配)某些特定测试的所有文件,然后对它们执行某些操作。对于这个特定问题,您可以使用:

find -type f ! \( -iname '*.png' -o -iname '*.gif' -o -iname '*.jpg' -o -iname '*.xcf' \) -exec echo mv {} /new/path \;
Run Code Online (Sandbox Code Playgroud)

这会将搜索限制为常规文件 ( -type f),然后搜索名称中没有 ( !)*.png任何大小写 ( -iname '*.png') 或 ( -o)扩展名的文件*.gif,依此类推。所有扩展名都被分组到\( ... \). 对于每个匹配的文件,它运行一个命令 ( -exec),将文件的名称插入{}目录中,以代替/new/path。该\;通知find命令是结束了。

名称替换发生在程序执行代码中,因此空格和其他特殊字符无关紧要。


如果您只想在 Bash 中执行此操作,则可以使用 Bash 的扩展模式匹配功能。这些要求shopt extglob也开启globstar了。在这种情况下,请使用:

mv **/!(*.[gG][iI][fF]|*.[pP][nN][gG]|*.[xX][cC][fF]|*.[jJ][pP][gG]) /new/path
Run Code Online (Sandbox Code Playgroud)

这将匹配子目录 ( **) 中不匹配*.gif*.png等的所有文件,以任何字符大小写组合,并将它们移动到新路径中。扩展由 shell 执行,因此空格和特殊字符不再重要。

以上假设所有文件都在子目录中。如果没有,您可以重复后面的部分**/以包含当前目录。

zsh和其他 shell 中也有类似的功能,但您已经表明您正在使用 Bash。


(进一步注意:解析ls从来都不是一个好主意 - 只是不要尝试。)

  • 前几天有一个关于引用变量扩展的内容(顺便说一下,它们是为了它);我同意它通常有点热情。顺便说一下,我也同意链接的答案显示了解析 `ls` 的容易程度,但我认为我们在解析的容易程度方面存在分歧——这是一项非常聪明的工作。所以“永远不要这样做”仍然是很好的一般建议*对于任何需要建议的人* (3认同)