如何将文件从具有相同目录名的子目录移动到其相对上层/父目录?

如何将文件从具有相同目录名的子目录移动到其相对上层/父目录?

因此,我有一个这样的目录结构:

parent/
├── sub1
│   └── source
│       └── file1
│       └── file2
├── sub2
│   └── sub2.1
│       └── source
│           └── something1
│           └── something2
└── sub3
    └── sub3.1
        └── sub3.1.1
            └── source
                └── other.zip

我想搬家全部文件(文件名不同)来自所有目录均已命名source到其相对上级/父目录。因此,结果应该是这样的:

parent/
├── sub1
│   ├── file1
│   ├── file2
│   └── source
├── sub2
│   └── sub2.1
│       ├── something1
│       ├── something2
│       └── source
└── sub3
    └── sub3.1
        └── sub3.1.1
            ├── other.zip
            └── source

有没有简单的方法(一句话) 来完成此操作,也许使用find命令?最好是一个不太复杂以至于我难以理解的命令。:D 我对 Linux 还很陌生。

编辑:我还将利用该解决方案编写一个 bash 脚本(以便我可以轻松使用它)。例如:./movefiles.sh myfolder 因此,最好该解决方案可以轻松容纳变量,尤其是那些带有符号的变量.(如果它是隐藏目录),,,#等等@

答案1

启用选项的简单for循环globstar(运行shopt -s globstar即可执行)将完成该工作:

dirname="source"
for i in ./**/"$dirname"/; do
  mv "$i"* "${i%$dirname/}"
done

GNUparallel 平行安装该循环的等效项是:

parallel mv {}* {//}/ ::: ./**/"$dirname"/

一种完全不同的方法是rename从字符串中删除“$dirname/”部分:

rename "s/$dirname\///" **/"$dirname"/*

引用$像我在这里一样使用双引号可以保留除、`\之外的每个特殊字符的含义!。如果要在上述任何解决方案中包含“隐藏”点文件,请dotglob在运行之前设置选项:shopt -s dotglob

解释

globstar
如果设置,路径名扩展上下文中使用的模式**将匹配所有文件和零个或多个目录和子目录。如果模式后跟/,则仅匹配目录和子目录。

./**/source/匹配source当前目录下的每个目录,该mv命令将目录内部的每个文件移动到其父目录 -是一个参数扩展,它从(路径)字符串的末尾${i%source/}删除字符串。source/

示例运行

$ tree
.
├── sub1
│   └── source
│       ├── file1
│       └── file2
├── sub2
│   └── sub2.1
│       └── source
│           ├── something1
│           └── something2
└── sub3
    └── sub3.1
        └── sub3.1.1
            └── source
                └── other.zip

$ dirname="source"
$ for i in ./**/"$dirname"/; do mv "$i"* "${i%$dirname/}"; done
$ tree
.
├── sub1
│   ├── file1
│   ├── file2
│   └── source
├── sub2
│   └── sub2.1
│       ├── something1
│       ├── something2
│       └── source
└── sub3
    └── sub3.1
        └── sub3.1.1
            ├── other.zip
            └── source

答案2

如果你想要一个find解决方案,你可以使用这个:

find parent -name "source" -type d -exec bash -c 'cd "$1"; mv * ..' bash {} \;

解释:

  • find parent -name "source" -type dsource- 对于以parent...命名的每个目录
  • -exec bash -c '...' bash {} \;- 使用bashas调用 Bash $0,并将目录路径作为$1
  • cd "$1"; mv * ..- cd 进入目录;将其所有内容上移一级。
    • 选择:mv "$1"/* "$1/.."

这或多或少基于甜点的答案

包括隐藏文件

find parent -name "source" -type d -exec bash -c 'shopt -s dotglob; cd "$1"; mv * ..' bash {} \;
  • shopt -s dotglob- 使 glob 包含隐藏文件

答案3

您可以使用下面的代码来获得您想要的内容:

dir=$(find . -name 'source' | sed s:source::)
for path in $dir; do
    mv "$path"source/* "$path"
done

find命令返回从父目录到源目录的目录路径。其中find . -name 'source'“.”代表父目录,“源”代表要查找的子目录。

该命令从命令结果中sed删除。sourcefind

剩下的只是迭代(for)和移动命令(mv

答案4

嵌套的 find 命令将在一行中完成该任务,但这可能看起来有点古怪。;-)

具体来说:

find . -name source -type d -exec sh -c 'find "$0" -type f -execdir mv "{""}"  .. \;' {} \;

解释:

  • find . -name source -type dsource查找当前 ( .) 目录中命名的所有目录。

  • -exec sh -c '...' {} \;对每个找到的目录执行shwith 命令'...',将目录名插入到 中{},并进一步使用 的内容定义执行sh的 变量(请参阅手册页中的选项)$0{}-csh

  • 的参数sh -c,'find "$0" -type f ... '查找目录内的所有文件$0

  • 最后... -execdir mv "{""}" ..将找到的文件{}(此处隐藏以"{""}"防止由于上游而导致的替换-exec)移动到(目录本地 - 因此-execdir)父目录..

示例运行:

marcus@gargabuntu:~/temp$ tree
.
├── sub1
│   └── source
│       ├── file1
│       └── file2
├── sub2
│   └── sub2.1
│       └── source
│           ├── something1
│           └── something2
└── sub3
    └── sub3.1
        └── sub3.1.1
            └── source
                └── other.zip

9 directories, 5 files
marcus@gargabuntu:~/temp$ find . -name source -type d -exec sh -c 'find "$0" -type f -execdir mv "{""}"  .. \;' {} \;
marcus@gargabuntu:~/temp$ tree
.
├── sub1
│   ├── file1
│   ├── file2
│   └── source
├── sub2
│   └── sub2.1
│       ├── something1
│       ├── something2
│       └── source
└── sub3
    └── sub3.1
        └── sub3.1.1
            ├── other.zip
            └── source

9 directories, 5 files

相关内容