文件系统的递归搜索和移动

文件系统的递归搜索和移动

我有一个文件系统,我想按字母顺序排列。它很大,手动操作会花很长时间。

我想知道的是,是否可以在终端中写入一些内容来创建文件夹 AZ,然后让终端搜索整个文件系统并将所有子文件夹移动到各自的字母文件夹中。

我还希望根据子文件夹中的文件扩展名来组织搜索。

例如,查找并移动所有以字母 A 开头且文件扩展名是 .doc 的子文件夹到 folderA。

提前致谢

答案1

您可以使用find以下命令以递归方式(深度优先)将所有文件夹移动到以其文件名首字母命名的文件夹中,如果该文件夹尚不存在,则从当前工作目录开始创建该文件夹:

find . -depth -mindepth 1 -type d -execdir bash -c 'l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/"' \;

解释:

  • find . -depth -mindepth 1 -type d -execdir <COMMAND> \;
    .以深度优先 ( ) 的 方式递归搜索当前目录 ( ) 中的-depth所有目录 ( -type d),但不包括当前目录本身 ( -mindepth 1)。
    然后,它cd会进入每个找到的文件夹的父目录并<COMMAND>从那里执行,将每个出现的 替换{}为找到的相对目录名称 ( -execdir)。
  • bash -c '<COMMAND>'
    启动 Bash 子 shell 并让其解释和执行字符串<COMMAND>。我们需要这样做是因为我们将使用变量、管道、命令替换等 shell 功能,而这些功能无法通过 直接完成find -execdir
  • l=./$(basename "{}" | head -c1)
    将找到的目录名称的首字母(记住{}用搜索结果替换)存储在 shell 变量中$l
  • test -d "${l^^}" || mkdir "${l^^}"
    检查目录是否存在,如果不存在则创建目录。目录的名称 ( "${l^^}") 是变量的内容$l(找到的目录名称的首字母)转换为大写。

  • mv "{}" "${l^^}/"
    将找到的目录(再次记住{}被替换的目录)移动到以其首字母转换为大写命名的目录中(“${l^^}/”,我们之前准备的)。

示例运行:

$ tree -F
.
├── apple/
│   ├── hamster/
│   ├── horse/
│   ├── snake/
│   │   ├── blue
│   │   ├── green
│   │   ├── grey
│   │   └── red
│   └── spider/
├── apricot/
├── banana/
├── cherry/
│   ├── pink
│   ├── purple
│   └── yellow
└── coconut/

9 directories, 7 files
$ find . -depth -mindepth 1 -type d -execdir bash -c 'l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/"' \;
$ tree -F
.
├── A/
│   ├── apple/
│   │   ├── H/
│   │   │   ├── hamster/
│   │   │   └── horse/
│   │   └── S/
│   │       ├── snake/
│   │       │   ├── blue
│   │       │   ├── green
│   │       │   ├── grey
│   │       │   └── red
│   │       └── spider/
│   └── apricot/
├── B/
│   └── banana/
└── C/
    ├── cherry/
    │   ├── pink
    │   ├── purple
    │   └── yellow
    └── coconut/

14 directories, 7 files

编辑:

如果您希望它非递归,即仅对当前工作目录的直接第一级子目录进行操作,只需-maxdepth 1在命令中添加选项即可。但是,find您可以省略该选项:-depth

find . -mindepth 1 -maxdepth 1 -type d -execdir bash -c 'l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/"' \;

编辑2:

只有当要移动的目录包含符合特定条件的文件时才可以执行移动(此处:包含文件名以.jpg任何位置结尾的文件,包括子目录),但它会添加另一个find命令和一个if子句:

find . -depth -mindepth 1 -maxdepth 1 -type d -execdir bash -c 'if find "{}" -type f -iname '*.jpg' | grep -q '.' ; then l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/" ; fi' \;

解释(第 2 次编辑后):

  • if <CONDITION> ; then <COMMANDS> ; fi
    检查命令的退出代码,并且仅在条件满足(退出代码 0)时<CONDITION>运行和<COMMANDS>之间。与以前的版本相同。thenfi<COMMANDS>
  • find "{}" -type f -iname '*.jpg' | grep -q '.' 在外部命令找到的目录中搜索find(再次记住将{}被替换)-type f名称以 结尾的文件( ).jpg,不区分大小写(-iname '*.jpg')。只是
    检查grep -q '.'是否find在 STDOUT 上产生任何输出(意味着找到了文件)并返回退出代码 0,如果未找到任何文件,则返回 1。

示例运行(编辑 2 之后):

$ tree -F
.
├── apple/
│   ├── hamster/
│   ├── horse/
│   ├── snake/
│   │   ├── blue
│   │   ├── green
│   │   ├── grey
│   │   └── red
│   └── spider/
├── apricot/
├── banana/
│   └── black.jpg
├── cherry/
│   ├── pink
│   ├── purple
│   └── yellow
└── coconut/

9 directories, 8 files

$ find . -depth -mindepth 1 -maxdepth 1 -type d -execdir bash -c 'if find "{}" -type f -iname '*.jpg' | grep -q '.' ; then l=./$(basename "{}" | head -c1) ; test -d "${l^^}" || mkdir "${l^^}" ; mv "{}" "${l^^}/" ; fi' \;
$ tree -F
.
├── A/
│   └── apple/
│       ├── hamster/
│       ├── horse/
│       │   └── white.jpg
│       ├── snake/
│       │   ├── blue
│       │   ├── green
│       │   ├── grey
│       │   └── red
│       └── spider/
├── apricot/
├── B/
│   └── banana/
│       └── black.jpg
├── cherry/
│   ├── pink
│   ├── purple
│   └── yellow
└── coconut/

11 directories, 9 files

相关内容