![根据文件的父目录重命名文件](https://linux22.com/image/4933/%E6%A0%B9%E6%8D%AE%E6%96%87%E4%BB%B6%E7%9A%84%E7%88%B6%E7%9B%AE%E5%BD%95%E9%87%8D%E5%91%BD%E5%90%8D%E6%96%87%E4%BB%B6.png)
我有一个主目录,比如说main
.该主目录有一些文件夹,其中有三个名为ccc
ddd
和的文件夹lll
,这是我想要定位和处理的唯一文件夹。每个子文件夹中都有一些文件夹,这些文件夹在三个子文件夹中的名称都相同,因此ccc
ddd
lll
子文件夹中包含相同名称的文件夹。
然后,其中的每个子子文件夹ccc
ddd
lll
都有许多以特定名称命名的文件,例如 this c_000
d_000
l_000
,c_001
d_001
l_001
等等。
我首先要做的是重命名这些文件,以便它们的两个父目录将附加在文件名的开头,如下所示ccc_foo1_c_000
ddd_foo1_d_000
lll_foo1_l_000
。我问是否有人可以建议我如何在脚本中完成此操作.sh
?
这是我的主文件夹的简单树形结构:
.
`-- main
|-- ccc
| `-- foO1
| | |-- c_000
| | `-- c_001
| |
-- foo2
| |-- c_000
| `-- c_001
|
|
|-- ddd
| `-- foO1
| | |-- d_000
| | `-- d_001
| |
-- foo2
| |-- d_000
| `-- d_001
|-- lll
| `-- foO1
| | |-- l_000
| | `-- l_001
| |
| -- foo2
| |-- l_000
| `-- l_001
|
|-- aaa
|-- bbb
答案1
你可以这样做:
for dir in ccc ddd lll; do
find "main/$dir" -type f -print0 |
while IFS= read -r -d '' f; do
dd=$(dirname "$f")
new="${f/main\/}"
new="${new//\//_}"
mv "$f" "$dd"/"$new"
done
done
完成上述脚本后,您的文件将如下所示:
.
`-- main
|-- ccc
| |-- fo01
| | |-- ccc_fo01_c_000
| | `-- ccc_fo01_c_001
| `-- fo02
| |-- ccc_fo02_c_000
| `-- ccc_fo02_c_001
|-- ddd
| |-- fo01
| | |-- ddd_fo01_d_000
| | `-- ddd_fo01_d_001
| `-- fo02
| |-- ddd_fo02_d_000
| `-- ddd_fo02_d_001
`-- lll
|-- fo01
| |-- lll_fo01_l_000
| `-- lll_fo01_l_001
`-- fo02
|-- lll_fo02_l_000
`-- lll_fo02_l_001
解释
for dir in ccc ddd lll; do ...; done
:仅对这三个目录名称执行此操作,将它们分别保存为$dir
.find "main/$dir" -type f -print0 |
:查找type f
中的所有文件 ( )main/$dir
,并以空字符串 (-print0
) 分隔打印它们,以确保即使文件/目录名称包含换行符也能正常工作。while IFS= read -r -d '' f; do
:这将迭代结果find
,将每个结果保存为$f
.需要IFS=
避免打破空白,这样-r
反斜杠就不会被特殊处理,并且-d ''
允许读取空分隔的输入。dd=$(dirname "$f")
:$dd
现在是当前文件所在的目录。例如,main/ccc/fo01
。new="${f/main\/}"
:这是使用外壳的字符串操作main/
从文件路径中删除字符串的能力。new="${new//\//_}"
:如上所述,现在我们将所有内容替换/
为下划线。这会产生类似 的字符串ccc_fo01_c000
。mv "$f" "$dd"/"$new"
:最后,我们将原始文件重命名$f
为$dd/$new
.请记住,这$dd
是该文件所在的目录,并且$new
现在是您要将其重命名为的名称。
我建议您在实际执行此操作之前在测试echo
之前添加一个mv
。
答案2
这是一个简单的 POSIX shell 解决方案,它循环文件、解析名称的目录部分并逐个重命名它们。
for x in ccc/*/* ddd/*/* lll/*/*; do
dir2=${x%/*}; dir1=${dir2%/*}; dir2=${dir2#"$dir1"}
mv -- "$x" "${x%/*}/${dir1}_${dir2}_${x##*/}"
done
在 bash 中,您可以使用参数扩展字符串替换功能以避免解析文件名。
for x in ccc/*/* ddd/*/* lll/*/*; do
mv -- "$x" "${x%/*}/${x//\//_}"
done
在 zsh 中,您可以使用zmv
根据模式重命名文件。
autoload -U zmv
zmv '(ccc|ddd|lll)/(*)/(*)' '$1/$2/${1}_${2}_$3'
答案3
对于从目录中运行的软编码解决方案main
:
#!/bin/bash
for f in $(find . -name '*_00*'); do
mv "$f" "$(dirname "$f")/$(dirname "${f:2}" | tr "/" "_")_$(basename $f)"
done
这应该递归地遍历所有目录,查找包含该模式的所有文件*_00*
。每个文件均使用由路径 ( $(dirname $"f")
)、包含下划线和删除的前两个字符的转换路径 ( $(dirname "${f:2}" | tr "/" "_")
) 以及原始文件名本身 ( $(basename $f)
) 组成的组合单独重命名。