将文件重命名为终端中的父目录名称
我必须处理嵌套在目录中的大量文件(每个目录一个文件),类似于:
fred/result.txt john/result.txt mary/result.txt ...
我目前正在使用以下命令来处理每个文件:
find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c \"cd '{}' && processResult result.txt\" \;
我正在寻找可以添加到此命令末尾的内容,它将文件名更改为fred.txt
等,然后将文件移动到父目录中以消除额外的目录层。
最好的方法是什么?
我们可以使用经典的方法:用while read
组合:
演示:
$ ls * fred: results.txt jane: results.txt john: results.txt $> find . -type f -name "results.txt" -printf "/%P\n" | while read FILE ; do DIR=$(dirname "$FILE" );\ > mv ."$FILE" ."$DIR""$DIR".txt;done $> ls fred/ jane/ john/ $> ls * fred: fred.txt jane: jane.txt john: john.txt
在使用mv
测试该文件的行之前使用echo
。
小改进
我们可以通过参数扩展(特别是前缀删除)将对bash
的调用嵌入到exec中。 基本上它是将脚本嵌入到exec调用中。
$> find "$PWD" -type f -name "results.txt" -exec bash -c ' DIR=$( dirname "{}" ); echo "{}" "$DIR"/"${DIR##*/}".txt ' \; /home/xieerqi/TESTDIR/fred/results.txt /home/xieerqi/TESTDIR/fred/fred.txt /home/xieerqi/TESTDIR/jane/results.txt /home/xieerqi/TESTDIR/jane/jane.txt /home/xieerqi/TESTDIR/john/results.txt /home/xieerqi/TESTDIR/john/john.txt
要使命令通用,(为任何文件工作,而不仅仅是results.txt
)只需删除-name "results.txt"
部分。 另请参阅此文章,了解替代Python解决方案。
我认为这是合法的(使用基于perl的rename
命令)
find dir -name 'results.txt' -exec rename -nv -- 's|/(.*)/(.*)$|/$1/$1.txt|' {} +
例如,给定
$ tree dir dir ├── fred │ └── results.txt ├── john │ └── results.txt └── mary └── results.txt 3 directories, 3 files
然后
$ find dir -name 'results.txt' -exec rename -v -- 's|/(.*)/(.*)$|/$1/$1.txt|' {} + dir/fred/results.txt renamed as dir/fred/fred.txt dir/john/results.txt renamed as dir/john/john.txt dir/mary/results.txt renamed as dir/mary/mary.txt
导致
$ tree dir dir ├── fred │ └── fred.txt ├── john │ └── john.txt └── mary └── mary.txt 3 directories, 3 files
如果你只需要低于目标1级,你可以简单地做到
rename -vn -- 's|/(.*)/(.*)$|/$1/$1.txt|' dir/*/results.txt
与往常一样, -n
选项留待测试
下面的小python脚本将完全按照你的描述完成; 它会:
- 根据其上级目录重命名给定目录中的任何文件,名为
results.txt
- 将它移动一个(目录)级别
- 删除文件最初所在的(现在为空)目录
结果:
这个:
directory | ├── fred │ └── results.txt ├── john │ └── results.txt └── mary └── results.txt
会变成:
directory | ├── fred.txt │ ├── john.txt │ └── mary.txt
剧本
#!/usr/bin/env python3 import shutil import os import sys dr = sys.argv[1] for root, dirs, files in os.walk(dr): for file in files: if file == "results.txt": spl = root.split("/"); newname = spl[-1]; sup = ("/").join(spl[:-1]) shutil.move(root+"/"+file, sup+"/"+newname+".txt"); shutil.rmtree(root)
使用
- 将下面的代码复制到一个空文件中,将其另存为
move_rename.py
-
通过命令运行它:
python3 /path/to/move_rename.py
注意
一如既往,首先在小样本上进行测试
通过查找来看似乎过于复杂。 为什么不使用简单的for循环?
for folder in *; do (cd "$folder" && processResult result.txt) # This replaces your previous find(1) mv "$folder/result.txt" "${folder}.txt" rmdir "$folder" done
如果在具有相同扩展名的文件夹中有多个文件,则上述某些命令将覆盖除一个以外的所有文件,重命名具有相同名称的所有文件。
folder1/file1.txt file2.txt --> folder1/folder1.txt
为避免这种情况,您可以使用此命令或等效命令:
for f in */*.txt ;do fp=$(dirname "$f"); fl=$(basename "$f"); mv "$fp/$fl" "$fp/$fp"_"$fl"; done
通过保留完整文件名$ fl而不仅仅是扩展名,您可以保留所有文件。
folder1/file1.txt file2.txt --> folder1/folder1_file1.txt folder1_file2.txt