根据父目录移动和重命名文件

根据父目录移动和重命名文件

我有一组目录,它们都包含在所有目录中同名的特定文件。

dir1/dirA/file.txt
dir1/dirB/file.txt
dir1/dirC/file.txt
....
dir4/dirX/file.txt
dir4/dirY/file.txt
dir4/dirZ/file.txt

我想将这些文件复制到另一个目录中,以便每个文件的名称都是其父目录的名称:

all_files/
    dirA.txt
    dirB.txt
    dirC.txt
    ....
    dirX.txt
    dirY.txt
    dirZ.txt

虽然我理解这些示例可能会导致重叠,但这对我来说不是问题——我知道所有目标目录都有唯一的名称。

我在 OS X 中使用 bash。我尝试做了几件类似的事情(参见这里这里)。我的想法是将字符串拆分为斜线,得到倒数第二个,然后使用它,但我无法让它工作(基于和别的):

for name in `ls */*/file`
    directory=${DIRS[${#DIRS[@]} - 2]}
    mv name ../all_files/${directory}.txt
done

但是,我无法让它工作。

答案1

for name in ./*/*/file.txt
do
    mv "$name" "../all_files/$(basename -- "$(dirname -- "$name")").txt"
done

一些评论:

  • 永远不要做这样的事或者类似的事情:

    for name in `ls */*/file`
    

    如果文件名中有空格或其他难理解的字符,上述操作将失败。请使用:

    for name in ./*/*/file
    

    无论文件名多么奇怪,shell 都会正确处理上述内容。

  • 这存在多个问题:

    mv name ../all_files/${directory}.txt
    

    最重要的是,这将移动名为 的文件name。您更希望移动变量引用的文件name。为此使用"$name"而不是name。请注意此处使用双引号。这可以防止名称被拆分,这样即使文件名中有空格或其他困难字符,此方法也能正常工作。

    同样,目标位置也应该用双引号引起来。

答案2

我对此进行了一番思考,并找到了两个解决方案。第一个使用 basename 和 dirname:

for name in */*/file
    do cp $name ../all_files/$(basename -- "$(dirname -- "$name")")
done

这个使用字符串分割(正如我最初想做的那样)

for name in */*/choices
    do parts=(${name//\// })
    directory=${parts[${#parts[@]} - 2]}
    cp $name all_files/${directory}.txt
done

希望这对某人有帮助!

相关内容