给定包含许多不同文件类型(csv,txt,jpg 等)的许多目录/子目录,什么命令将递归搜索每个目录并将文件复制到以每个扩展名命名的新顶级目录中。
有没有办法用一行代码来实现这个目的?
答案1
解决方案
以下命令将列出当前目录 ( .
) 中的所有文件并将它们移动到以其扩展名命名的目录中./OUTPUT
:
for file in $(find . -type f) ; do EXTENSION=$(echo "$file" |sed 's/.*\.//g') ; rsync -av $file ./OUTPUT/$EXTENSION/ ; done
在运行上述命令之前,您需要:
- 在当前目录中创建目录 OUTPUT (
mkdir OUTPUT
) - 确保任何子目录中都没有名称匹配的文件
解释
首先,循环将file
的输出中的一个文件赋值给变量find . -type f
。该命令的示例输出find
如下:
./a/myfile1.zip
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/myfile3.zip
./a/myfile4.zip
./a/myfile2.zip
变量EXTENSION
已创建,其值是file
删除了最后一个句号的变量。因此./a/myfile1.zip
将变成zip
。
然后将该文件同步(详细程度)到以文件扩展名命名的v
目录中。OUTPUT
在某些测试上运行此命令后我的文件树的示例:
./a
./a/b
./a/b/adoc1.txt
./a/b/adoc2.txt
./a/b/adoc3.txt
./a/b/adoc4.txt
./a/b/c
./a/myfile1.zip
./a/myfile2.zip
./a/myfile3.zip
./a/myfile4.zip
./b
./b/c
./b/c/d
./b/c/file1.txt
./b/c/file2.txt
./b/c/file3.txt
./b/c/file4.txt
./c
./c/d
./c/d/e
./c/d/e/afile1.rar
./c/d/e/afile2.rar
./c/d/e/afile3.rar
./c/d/e/afile4.rar
./OUTPUT
./OUTPUT/rar
./OUTPUT/rar/afile1.rar
./OUTPUT/rar/afile2.rar
./OUTPUT/rar/afile3.rar
./OUTPUT/rar/afile4.rar
./OUTPUT/txt
./OUTPUT/txt/adoc1.txt
./OUTPUT/txt/adoc2.txt
./OUTPUT/txt/adoc3.txt
./OUTPUT/txt/adoc4.txt
./OUTPUT/txt/file1.txt
./OUTPUT/txt/file2.txt
./OUTPUT/txt/file3.txt
./OUTPUT/txt/file4.txt
./OUTPUT/zip
./OUTPUT/zip/myfile1.zip
./OUTPUT/zip/myfile2.zip
./OUTPUT/zip/myfile3.zip
./OUTPUT/zip/myfile4.zip
答案2
这可以非常简单地完成寻找,正如 Alex 正确建议的那样:假设要扫描文件的目录是/path1/到/一些/目录,并且您希望将文件移动到/path2/to/other/dir/txt等等,
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir${0##*.}; [ -d $MYDIR ] && mv $0 $MYDIR || mv $0 /path3/to/miscellanea' {} \;
此命令首先查找所有文件(-类型 f)包含在目录中/path1/到/一些/目录及其所有子目录,然后传递每个此类文件的名称({}) 改为一行小的 bash 命令,首先从文件名中提取扩展名(称为$0在 bash 中),并将其分配给本地 shell 变量我的目录, 然后测试是否存在合适的目录(如果没有这样的目录,那么我们可能犯了一个错误),并且如果目录存在(&& ...)它会将文件移动到适当的目录中,否则(||...)将文件放置在默认位置,/path3/to/miscellanea。
以上假设您已经创建了必要的目录,/path2/to/other/dir/txt等等。如果你想要随时创建它们,则必须将上述内容修改为:
find /path1/some/dir -type f -exec bash -c 'MYDIR=/path2/to/other/dir/${0##*.}; mkdir -p $MYDIR && mv $0 $MYDIR' {} \;