我有一组目录,它们都包含在所有目录中同名的特定文件。
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
希望这对某人有帮助!