使用for循环将文件从子目录移动到父目录

4

我刚刚转换到linux系统并尝试编写我的第一个bash脚本。我有一个包含众多文件夹的文件夹,每个文件夹下面还有子文件夹和文件,就像这样:

  • 主文件夹

    • 文件夹1
      • 子文件夹1(包含许多文件)
      • 子文件夹2(包含许多文件)
    • 文件夹2
      • 子文件夹1(包含许多文件)
      • 子文件夹2(包含许多文件)

    ......

我想要将所有子文件夹中包含的文件移动到它们各自的父文件夹中。我的第一反应是尝试编写一个for循环。我使用以下命令可以一次处理一个文件夹:

mv MainFolder/Folder1/*/* MainFolder/Folder1/

我希望编写一个 Bash 脚本循环遍历主目录中的所有文件夹。以下是我的代码:

#!/bin/bash

dir1="/pathto/MainFolder"

subs= ls $dir1

for i in $subs; do
  mv "$dir1/$i/*/*" "$dir1/$i/" 
done

显然,这样做是无效的,但我不明白哪里出了问题。
我还尝试过:
mv MainFolder/*/*/* MainFolder/*/

结果非常糟糕。一旦我成功地完成文件移动,我还想在循环内部删除旧的子文件夹。


你想如何处理 MainFolder/Folder1/Sub1/foo.txtMainFolder/Folder1/Sub2/foo.txt? 如果文件名冲突,你是否可以接受一些文件被删除的情况? - twalberg
在我的情况下不会出现任何名称冲突,但我很想知道如何处理这种情况。 - dayne
这取决于您的决定 - 处理它有许多方法,其中两个明显的方法是1)不移动第二个和后续冲突文件和2)以某种方式重命名所有冲突,使其不再冲突。但真正取决于您想要实现什么... - twalberg
3个回答

5

小改动。改动

subs=ls $dir1

为了

subs=`ls $dir1`

注意反引号。反引号实际上执行bash命令并返回结果。如果在该行后输入echo $subs,您会发现它正确地列出了folder1folder2
第二个小改变是删除mv命令中的双引号。将它们改为
mv $dir1/$i/*/* $dir1/$i

双引号使用字面文件名,而去除引号则采用递归目录模式。

之后,您的初始for循环是正确的。它将把sub1sub2中的所有内容移动到folder1等等。


按照已接受的答案所描述的方式处理“ls”会引入一些陷阱,包括无法处理包含空格的目录名称。请参见https://mywiki.wooledge.org/BashPitfalls#for_f_in_.24.28ls_.2A.mp3.29和https://superuser.com/questions/1191472/move-each-file-into-its-parent-directory-in-linux。 - user2514157

1
是的 - 这是有效的解决方案。
#!/bin/bash

mainDir="$(dirname $(realpath $0))/store/media"

subs=`ls $mainDir`

for i in $subs; do
    if [[ -d "$mainDir/$i" ]]; then
        mv "$mainDir/$i"/* "$mainDir/"
        rm -rf "$mainDir/$i"
    fi
done


“/store/media” 应该被移除,脚本应该在子文件夹的同一级别运行。 - giammi56

0

!/bin/bash

dir1="/pathto/MainFolder"

subs=ls $dir1

for i in $subs; do

mv $dir1/$i// $dir1/$i

done

!/bin/bash

dir1="/pathto/MainFolder"

subs=`ls $dir1`

for i in $subs; do

mv $dir1/$i// $dir1/$i

done


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接