我有这个文件夹结构:
├── foo1
│ ├── bar1.txt
│ └── bar2.txt
├── foo2
│ ├── bar3.txt
│ └── bar4 with a space.txt
└── foo3
└── qux1
├── bar5.txt
└── bar6.txt
我想将其扁平化,在每个文件夹级别之间使用下划线:
├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt
我环顾四周,没有找到任何有效的解决方案,主要是因为我的问题有两个特殊性:根文件夹内可能有多个文件夹级别,而且有些文件可能有空格。
知道如何在 bash 中实现这一点吗?谢谢!
编辑:运行格伦·杰克曼提出的答案我得到这个:
一级文件夹有两个下划线。知道如何避免这种情况或只是重命名它,以便这只是一个下划线吗?谢谢。
答案1
find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;
echo
如果您对它的工作感到满意,请将其删除。不要担心 echo 命令不显示引号,脚本将正确处理带有空格的文件。
如果您想删除现在空的子目录:
find */ -depth -type d -exec echo rmdir '{}' \;
答案2
使用perl的重命名:
find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;
输出
$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt
笔记
- 我用一个消极地向后看
(?<!\.)
不要碰第一个./
我保留空目录,请随意:
find . -depth -type d -exec rm {} \;
还有其他同名的工具可能能够也可能无法做到这一点,所以要小心。
如果运行以下命令 ( GNU
)
$ file "$(readlink -f "$(type -p rename)")"
你有一个像这样的结果
.../rename: Perl script, ASCII text executable
并且不包含:
ELF
那么这似乎是正确的工具 =)
如果不是,则将其设为默认值(通常已经是这种情况)Debian
并衍生如下Ubuntu
:
$ sudo update-alternatives --set rename /path/to/rename
(替换为您的命令/path/to/rename
的路径。perl's rename
如果您没有此命令,请搜索包管理器来安装它或手动做
最后但并非最不重要的一点是,这个工具最初是由 Perl 之父 Larry Wall 编写的。
答案3
和pax
...
pax -Xrwls '|/|_|g' */ "$PWD"
这将在当前目录中创建一个指向其子目录中所有文件的硬链接,_
并将/
.然后您可以检查结果并使用以下命令删除所有子目录...
rm -rf */
...一旦您确认结果符合您的喜好。
答案4
您可以尝试使用以下命令。
$ find -type f -exec bash -c 'mv $0 $(echo $0|sed "s/\//_/2")' {} \;
上述命令将移动文件,并且目录将保留,稍后可以删除。
$ ls
foo1_bar1.txt foo1_bar2.txt foo2_bar3.txt foo2_bar4.txt foo3_bar5.txt foo3_bar6.txt