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

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

当我从 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 }'

这列出了所有内容。我尝试在它的末尾使用 grep,但不知道如何让它与我给出的模式不匹配。 extglob 开关对 grep 没有多大帮助,尽管它对其他命令有帮助。

答案1

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

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

这将搜索限制为常规文件 ( -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

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

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

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


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

答案2

你使用 Ubuntu,所以你会找到 GNU,尝试:

find . -maxdepth 1 ! -iregex ".*\.\(jpg\|png\|gif\|xcf\)$" -exec mv -- -t /path/to/newdir "{}" +
  • -iregex使用正则表达式查找文件名,但不区分大小写,!否定正则表达式。

  • -exec command +运行文件匹配命令。就像使用find -print0with一样xargs -0。使用此功能,我们可以移动一个命令找到的多个文件mv,因此调用命令的总数小于匹配文件的数量。

  • -maxdepth 1限制find仅在当前目录中搜索,如果要递归,请将其删除。

答案3

没有必要把这个事情搞得太复杂!为什么不只是:

mkdir ../temp
mv  *.{jpg,png,gif,xcf} ../temp/
mv * /desired/target/directory/
mv ../temp/* .
rmdir ../temp

当然,这不适用于整个目录树,仅适用于一个平面文件目录。

相关内容