将文件重命名为终端中的父目录名称

我必须处理嵌套在目录中的大量文件(每个目录一个文件),类似于:

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