Flattening a nested directory
This is probably very simple, but I can't figure it out. I have a directory structure like this (dir2 is inside dir1):
/dir1
/dir2
|
--- file1
|
--- file2
What is the best way to 'flatten' this director structure in such a way to get file1 and file2 in dir1 not dir2.
files directory rename cp recursive
add a comment |
This is probably very simple, but I can't figure it out. I have a directory structure like this (dir2 is inside dir1):
/dir1
/dir2
|
--- file1
|
--- file2
What is the best way to 'flatten' this director structure in such a way to get file1 and file2 in dir1 not dir2.
files directory rename cp recursive
askubuntu.com/questions/633945/…
– Ferroao
Dec 12 '17 at 14:55
add a comment |
This is probably very simple, but I can't figure it out. I have a directory structure like this (dir2 is inside dir1):
/dir1
/dir2
|
--- file1
|
--- file2
What is the best way to 'flatten' this director structure in such a way to get file1 and file2 in dir1 not dir2.
files directory rename cp recursive
This is probably very simple, but I can't figure it out. I have a directory structure like this (dir2 is inside dir1):
/dir1
/dir2
|
--- file1
|
--- file2
What is the best way to 'flatten' this director structure in such a way to get file1 and file2 in dir1 not dir2.
files directory rename cp recursive
files directory rename cp recursive
edited Oct 25 '12 at 0:01
Gilles
532k12810661592
532k12810661592
asked Oct 24 '12 at 19:28
turtleturtle
84221316
84221316
askubuntu.com/questions/633945/…
– Ferroao
Dec 12 '17 at 14:55
add a comment |
askubuntu.com/questions/633945/…
– Ferroao
Dec 12 '17 at 14:55
askubuntu.com/questions/633945/…
– Ferroao
Dec 12 '17 at 14:55
askubuntu.com/questions/633945/…
– Ferroao
Dec 12 '17 at 14:55
add a comment |
5 Answers
5
active
oldest
votes
You can do this with GNU find
and GNU mv
:
find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +
Basically, the way that works if that find
goes through the entire directory tree and for each file (-type f
) that is not in the top-level directory (-mindepth 2
), it runs a mv
to move it to the directory you want (-exec mv … +
). The -t
argument to mv
lets you specify the destination directory first, which is needed because the +
form of -exec
puts all the source locations at the end of the command.
As Stephane Chazelas points out, the above only works with GNU tools (which are standard on Linux, but not most other systems). The following is somewhat slower (because it invokes mv
multiple times) but much more universal:
find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
3
Edited to use-exec +
so that it doesn't execute a large number of processes ofmv
– Random832
Oct 24 '12 at 19:32
1
@Random832 And going to revert again, because + doesn't work.mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)
– derobert
Oct 24 '12 at 19:34
1
@Random832 but I supposemv
has a-t
we can use, so I'll change it to that.
– derobert
Oct 24 '12 at 19:36
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
1
@Domfind
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.
– derobert
Jul 15 '13 at 15:32
|
show 3 more comments
In zsh:
mv dir1/*/**/*(.D) dir1
**/
traverses subdirectories recursively. The glob qualifier .
matches regular files only, and D
ensures that dot files are included (by default, files whose name starts with a .
are excluded from wildcard matches). To clean up now-empty directories afterwards, run rmdir dir1/**/*(/Dod)
— /
restricts to directories, and od
orders the matches depth first so as to remove dir1/dir2/dir3
before dir1/dir2
.
If the total length of the file names is very large, you may run into a limitation on the command line length. Zsh has builtins for mv
and rmdir
which are not affected by this limitation: run zmodload zsh/files
to enable them.
With only POSIX tools:
find dir1 -type f -exec mv {} dir1 ;
find dir1 -depth -exec rmdir {} ;
or (faster because it doesn't have to run a separate process for each file)
find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +
1
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
add a comment |
Try doing this :
cp /dir1/dir2/file{1,2} /another/place
or for each files matching file[0-9]*
in the subdir :
cp /dir1/dir2/file[0-9]* /another/place
See http://mywiki.wooledge.org/glob
I should have indicated this, but I have to many files to use{}
in my real problem.
– turtle
Oct 24 '12 at 19:30
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
add a comment |
I wrote two functions you can use together that do just that, you can limit the directory level by adding a -maxdepth $VAL
parameter.
# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder
#!/bin/bash
rmEmptyDirs(){
local DIR="$1"
for dir in "$DIR"/*/
do
[ -d "${dir}" ] || continue # if not a directory, skip
dir=${dir%*/}
if [ "$(ls -A "$dir")" ]; then
rmEmptyDirs "$dir"
else
rmdir "$dir"
fi
done
if [ "$(ls -A "$DIR")" ]; then
rmEmptyDirs "$DIR"
fi
}
flattenDir(){
local DIR="$1"
find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}
read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
flattenDir "$1" &
rmEmptyDirs "$1" &
echo "Done";
fi
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
add a comment |
Expanding on the popular answer for this question, since I had a use-case for flattening a directory containing files of the same name.
dir1/
├── dir2
│ └── file
└── dir3
└── file
In this case, the -i
(--interactive
) option passed to mv
wouldn't yield the desired result to flatten the directory structure and handle name conflicts. So it's simply replaced with --backup=t
(equivalent to --backup=numbered
). More documentation on the -b
(--backup
) option available at https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options.
Resulting in:
find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +
Which yields:
dir1/
├── dir2
├── dir3
├── file
└── file.~1~
add a comment |
Your Answer
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "106"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f52814%2fflattening-a-nested-directory%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
5 Answers
5
active
oldest
votes
5 Answers
5
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can do this with GNU find
and GNU mv
:
find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +
Basically, the way that works if that find
goes through the entire directory tree and for each file (-type f
) that is not in the top-level directory (-mindepth 2
), it runs a mv
to move it to the directory you want (-exec mv … +
). The -t
argument to mv
lets you specify the destination directory first, which is needed because the +
form of -exec
puts all the source locations at the end of the command.
As Stephane Chazelas points out, the above only works with GNU tools (which are standard on Linux, but not most other systems). The following is somewhat slower (because it invokes mv
multiple times) but much more universal:
find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
3
Edited to use-exec +
so that it doesn't execute a large number of processes ofmv
– Random832
Oct 24 '12 at 19:32
1
@Random832 And going to revert again, because + doesn't work.mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)
– derobert
Oct 24 '12 at 19:34
1
@Random832 but I supposemv
has a-t
we can use, so I'll change it to that.
– derobert
Oct 24 '12 at 19:36
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
1
@Domfind
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.
– derobert
Jul 15 '13 at 15:32
|
show 3 more comments
You can do this with GNU find
and GNU mv
:
find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +
Basically, the way that works if that find
goes through the entire directory tree and for each file (-type f
) that is not in the top-level directory (-mindepth 2
), it runs a mv
to move it to the directory you want (-exec mv … +
). The -t
argument to mv
lets you specify the destination directory first, which is needed because the +
form of -exec
puts all the source locations at the end of the command.
As Stephane Chazelas points out, the above only works with GNU tools (which are standard on Linux, but not most other systems). The following is somewhat slower (because it invokes mv
multiple times) but much more universal:
find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
3
Edited to use-exec +
so that it doesn't execute a large number of processes ofmv
– Random832
Oct 24 '12 at 19:32
1
@Random832 And going to revert again, because + doesn't work.mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)
– derobert
Oct 24 '12 at 19:34
1
@Random832 but I supposemv
has a-t
we can use, so I'll change it to that.
– derobert
Oct 24 '12 at 19:36
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
1
@Domfind
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.
– derobert
Jul 15 '13 at 15:32
|
show 3 more comments
You can do this with GNU find
and GNU mv
:
find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +
Basically, the way that works if that find
goes through the entire directory tree and for each file (-type f
) that is not in the top-level directory (-mindepth 2
), it runs a mv
to move it to the directory you want (-exec mv … +
). The -t
argument to mv
lets you specify the destination directory first, which is needed because the +
form of -exec
puts all the source locations at the end of the command.
As Stephane Chazelas points out, the above only works with GNU tools (which are standard on Linux, but not most other systems). The following is somewhat slower (because it invokes mv
multiple times) but much more universal:
find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
You can do this with GNU find
and GNU mv
:
find /dir1 -mindepth 2 -type f -exec mv -t /dir1 -i '{}' +
Basically, the way that works if that find
goes through the entire directory tree and for each file (-type f
) that is not in the top-level directory (-mindepth 2
), it runs a mv
to move it to the directory you want (-exec mv … +
). The -t
argument to mv
lets you specify the destination directory first, which is needed because the +
form of -exec
puts all the source locations at the end of the command.
As Stephane Chazelas points out, the above only works with GNU tools (which are standard on Linux, but not most other systems). The following is somewhat slower (because it invokes mv
multiple times) but much more universal:
find /dir1 -mindepth 2 -type f -exec mv -i '{}' /dir1 ';'
edited Oct 25 '12 at 5:32
answered Oct 24 '12 at 19:30
derobertderobert
72.9k8153210
72.9k8153210
3
Edited to use-exec +
so that it doesn't execute a large number of processes ofmv
– Random832
Oct 24 '12 at 19:32
1
@Random832 And going to revert again, because + doesn't work.mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)
– derobert
Oct 24 '12 at 19:34
1
@Random832 but I supposemv
has a-t
we can use, so I'll change it to that.
– derobert
Oct 24 '12 at 19:36
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
1
@Domfind
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.
– derobert
Jul 15 '13 at 15:32
|
show 3 more comments
3
Edited to use-exec +
so that it doesn't execute a large number of processes ofmv
– Random832
Oct 24 '12 at 19:32
1
@Random832 And going to revert again, because + doesn't work.mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)
– derobert
Oct 24 '12 at 19:34
1
@Random832 but I supposemv
has a-t
we can use, so I'll change it to that.
– derobert
Oct 24 '12 at 19:36
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
1
@Domfind
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.
– derobert
Jul 15 '13 at 15:32
3
3
Edited to use
-exec +
so that it doesn't execute a large number of processes of mv
– Random832
Oct 24 '12 at 19:32
Edited to use
-exec +
so that it doesn't execute a large number of processes of mv
– Random832
Oct 24 '12 at 19:32
1
1
@Random832 And going to revert again, because + doesn't work.
mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)– derobert
Oct 24 '12 at 19:34
@Random832 And going to revert again, because + doesn't work.
mv
needs the destination as the final argument, but + would have the sources as the final argument. Find wont even accept the syntax you changed it to (find: missing argument to `-exec'
)– derobert
Oct 24 '12 at 19:34
1
1
@Random832 but I suppose
mv
has a -t
we can use, so I'll change it to that.– derobert
Oct 24 '12 at 19:36
@Random832 but I suppose
mv
has a -t
we can use, so I'll change it to that.– derobert
Oct 24 '12 at 19:36
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
@Random832 See How can I use two bash commands in -exec of find command?
– Gilles
Oct 24 '12 at 22:10
1
1
@Dom
find
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.– derobert
Jul 15 '13 at 15:32
@Dom
find
prints hidden (dot) files by default. The depth is relative to the directory you pass to find.– derobert
Jul 15 '13 at 15:32
|
show 3 more comments
In zsh:
mv dir1/*/**/*(.D) dir1
**/
traverses subdirectories recursively. The glob qualifier .
matches regular files only, and D
ensures that dot files are included (by default, files whose name starts with a .
are excluded from wildcard matches). To clean up now-empty directories afterwards, run rmdir dir1/**/*(/Dod)
— /
restricts to directories, and od
orders the matches depth first so as to remove dir1/dir2/dir3
before dir1/dir2
.
If the total length of the file names is very large, you may run into a limitation on the command line length. Zsh has builtins for mv
and rmdir
which are not affected by this limitation: run zmodload zsh/files
to enable them.
With only POSIX tools:
find dir1 -type f -exec mv {} dir1 ;
find dir1 -depth -exec rmdir {} ;
or (faster because it doesn't have to run a separate process for each file)
find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +
1
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
add a comment |
In zsh:
mv dir1/*/**/*(.D) dir1
**/
traverses subdirectories recursively. The glob qualifier .
matches regular files only, and D
ensures that dot files are included (by default, files whose name starts with a .
are excluded from wildcard matches). To clean up now-empty directories afterwards, run rmdir dir1/**/*(/Dod)
— /
restricts to directories, and od
orders the matches depth first so as to remove dir1/dir2/dir3
before dir1/dir2
.
If the total length of the file names is very large, you may run into a limitation on the command line length. Zsh has builtins for mv
and rmdir
which are not affected by this limitation: run zmodload zsh/files
to enable them.
With only POSIX tools:
find dir1 -type f -exec mv {} dir1 ;
find dir1 -depth -exec rmdir {} ;
or (faster because it doesn't have to run a separate process for each file)
find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +
1
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
add a comment |
In zsh:
mv dir1/*/**/*(.D) dir1
**/
traverses subdirectories recursively. The glob qualifier .
matches regular files only, and D
ensures that dot files are included (by default, files whose name starts with a .
are excluded from wildcard matches). To clean up now-empty directories afterwards, run rmdir dir1/**/*(/Dod)
— /
restricts to directories, and od
orders the matches depth first so as to remove dir1/dir2/dir3
before dir1/dir2
.
If the total length of the file names is very large, you may run into a limitation on the command line length. Zsh has builtins for mv
and rmdir
which are not affected by this limitation: run zmodload zsh/files
to enable them.
With only POSIX tools:
find dir1 -type f -exec mv {} dir1 ;
find dir1 -depth -exec rmdir {} ;
or (faster because it doesn't have to run a separate process for each file)
find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +
In zsh:
mv dir1/*/**/*(.D) dir1
**/
traverses subdirectories recursively. The glob qualifier .
matches regular files only, and D
ensures that dot files are included (by default, files whose name starts with a .
are excluded from wildcard matches). To clean up now-empty directories afterwards, run rmdir dir1/**/*(/Dod)
— /
restricts to directories, and od
orders the matches depth first so as to remove dir1/dir2/dir3
before dir1/dir2
.
If the total length of the file names is very large, you may run into a limitation on the command line length. Zsh has builtins for mv
and rmdir
which are not affected by this limitation: run zmodload zsh/files
to enable them.
With only POSIX tools:
find dir1 -type f -exec mv {} dir1 ;
find dir1 -depth -exec rmdir {} ;
or (faster because it doesn't have to run a separate process for each file)
find dir1 -type f -exec sh -c 'mv "$@" dir1' _ {} +
find dir1 -depth -exec rmdir {} +
edited Oct 25 '12 at 8:54
answered Oct 25 '12 at 0:01
GillesGilles
532k12810661592
532k12810661592
1
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
add a comment |
1
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
1
1
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
This should be the accepted answer! Especially with the concise zsh version.
– Adamski
Sep 6 '17 at 10:18
add a comment |
Try doing this :
cp /dir1/dir2/file{1,2} /another/place
or for each files matching file[0-9]*
in the subdir :
cp /dir1/dir2/file[0-9]* /another/place
See http://mywiki.wooledge.org/glob
I should have indicated this, but I have to many files to use{}
in my real problem.
– turtle
Oct 24 '12 at 19:30
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
add a comment |
Try doing this :
cp /dir1/dir2/file{1,2} /another/place
or for each files matching file[0-9]*
in the subdir :
cp /dir1/dir2/file[0-9]* /another/place
See http://mywiki.wooledge.org/glob
I should have indicated this, but I have to many files to use{}
in my real problem.
– turtle
Oct 24 '12 at 19:30
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
add a comment |
Try doing this :
cp /dir1/dir2/file{1,2} /another/place
or for each files matching file[0-9]*
in the subdir :
cp /dir1/dir2/file[0-9]* /another/place
See http://mywiki.wooledge.org/glob
Try doing this :
cp /dir1/dir2/file{1,2} /another/place
or for each files matching file[0-9]*
in the subdir :
cp /dir1/dir2/file[0-9]* /another/place
See http://mywiki.wooledge.org/glob
answered Oct 24 '12 at 19:30
Gilles QuenotGilles Quenot
16k13951
16k13951
I should have indicated this, but I have to many files to use{}
in my real problem.
– turtle
Oct 24 '12 at 19:30
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
add a comment |
I should have indicated this, but I have to many files to use{}
in my real problem.
– turtle
Oct 24 '12 at 19:30
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
I should have indicated this, but I have to many files to use
{}
in my real problem.– turtle
Oct 24 '12 at 19:30
I should have indicated this, but I have to many files to use
{}
in my real problem.– turtle
Oct 24 '12 at 19:30
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
See my second solution
– Gilles Quenot
Oct 24 '12 at 19:31
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
Bingo. Thanks for the help. This is definitely the best solution.
– turtle
Oct 24 '12 at 19:34
add a comment |
I wrote two functions you can use together that do just that, you can limit the directory level by adding a -maxdepth $VAL
parameter.
# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder
#!/bin/bash
rmEmptyDirs(){
local DIR="$1"
for dir in "$DIR"/*/
do
[ -d "${dir}" ] || continue # if not a directory, skip
dir=${dir%*/}
if [ "$(ls -A "$dir")" ]; then
rmEmptyDirs "$dir"
else
rmdir "$dir"
fi
done
if [ "$(ls -A "$DIR")" ]; then
rmEmptyDirs "$DIR"
fi
}
flattenDir(){
local DIR="$1"
find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}
read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
flattenDir "$1" &
rmEmptyDirs "$1" &
echo "Done";
fi
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
add a comment |
I wrote two functions you can use together that do just that, you can limit the directory level by adding a -maxdepth $VAL
parameter.
# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder
#!/bin/bash
rmEmptyDirs(){
local DIR="$1"
for dir in "$DIR"/*/
do
[ -d "${dir}" ] || continue # if not a directory, skip
dir=${dir%*/}
if [ "$(ls -A "$dir")" ]; then
rmEmptyDirs "$dir"
else
rmdir "$dir"
fi
done
if [ "$(ls -A "$DIR")" ]; then
rmEmptyDirs "$DIR"
fi
}
flattenDir(){
local DIR="$1"
find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}
read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
flattenDir "$1" &
rmEmptyDirs "$1" &
echo "Done";
fi
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
add a comment |
I wrote two functions you can use together that do just that, you can limit the directory level by adding a -maxdepth $VAL
parameter.
# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder
#!/bin/bash
rmEmptyDirs(){
local DIR="$1"
for dir in "$DIR"/*/
do
[ -d "${dir}" ] || continue # if not a directory, skip
dir=${dir%*/}
if [ "$(ls -A "$dir")" ]; then
rmEmptyDirs "$dir"
else
rmdir "$dir"
fi
done
if [ "$(ls -A "$DIR")" ]; then
rmEmptyDirs "$DIR"
fi
}
flattenDir(){
local DIR="$1"
find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}
read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
flattenDir "$1" &
rmEmptyDirs "$1" &
echo "Done";
fi
I wrote two functions you can use together that do just that, you can limit the directory level by adding a -maxdepth $VAL
parameter.
# This scripts flattens the file directory
# Run this script with a folder as parameter:
# $ path/to/script path/to/folder
#!/bin/bash
rmEmptyDirs(){
local DIR="$1"
for dir in "$DIR"/*/
do
[ -d "${dir}" ] || continue # if not a directory, skip
dir=${dir%*/}
if [ "$(ls -A "$dir")" ]; then
rmEmptyDirs "$dir"
else
rmdir "$dir"
fi
done
if [ "$(ls -A "$DIR")" ]; then
rmEmptyDirs "$DIR"
fi
}
flattenDir(){
local DIR="$1"
find "$DIR" -mindepth 2 -type f -exec mv -i '{}' "$DIR" ';'
}
read -p "Do you wish to flatten folder: ${1}? " -n 1 -r
echo # (optional) move to a new line
if [[ $REPLY =~ ^[Yy]$ ]]
then
flattenDir "$1" &
rmEmptyDirs "$1" &
echo "Done";
fi
edited Aug 3 '18 at 7:52
answered Jul 25 '16 at 1:28
BrunoBruno
1113
1113
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
add a comment |
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Man, I just misused your script by forgetting the path argument, that just really fucked up my server. Ok, I'm the guy who copy paste things and misuse them, but guys, be wise and add checks / confirmations on scripts that delete / move stuffs like that...
– dulgan
Aug 1 '18 at 8:32
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Whoops! I am sorry to hear that. Hope you have a backup... I added a confirmation for future protection.
– Bruno
Aug 2 '18 at 10:34
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
Thanks @Bruno that's much better this way. My server is still running flawlessly, i commented the "flatten" part to just delete empty directories recursively from (and that was my error) root, until I saw an error that made me stop running the script.
– dulgan
Aug 2 '18 at 14:05
add a comment |
Expanding on the popular answer for this question, since I had a use-case for flattening a directory containing files of the same name.
dir1/
├── dir2
│ └── file
└── dir3
└── file
In this case, the -i
(--interactive
) option passed to mv
wouldn't yield the desired result to flatten the directory structure and handle name conflicts. So it's simply replaced with --backup=t
(equivalent to --backup=numbered
). More documentation on the -b
(--backup
) option available at https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options.
Resulting in:
find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +
Which yields:
dir1/
├── dir2
├── dir3
├── file
└── file.~1~
add a comment |
Expanding on the popular answer for this question, since I had a use-case for flattening a directory containing files of the same name.
dir1/
├── dir2
│ └── file
└── dir3
└── file
In this case, the -i
(--interactive
) option passed to mv
wouldn't yield the desired result to flatten the directory structure and handle name conflicts. So it's simply replaced with --backup=t
(equivalent to --backup=numbered
). More documentation on the -b
(--backup
) option available at https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options.
Resulting in:
find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +
Which yields:
dir1/
├── dir2
├── dir3
├── file
└── file.~1~
add a comment |
Expanding on the popular answer for this question, since I had a use-case for flattening a directory containing files of the same name.
dir1/
├── dir2
│ └── file
└── dir3
└── file
In this case, the -i
(--interactive
) option passed to mv
wouldn't yield the desired result to flatten the directory structure and handle name conflicts. So it's simply replaced with --backup=t
(equivalent to --backup=numbered
). More documentation on the -b
(--backup
) option available at https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options.
Resulting in:
find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +
Which yields:
dir1/
├── dir2
├── dir3
├── file
└── file.~1~
Expanding on the popular answer for this question, since I had a use-case for flattening a directory containing files of the same name.
dir1/
├── dir2
│ └── file
└── dir3
└── file
In this case, the -i
(--interactive
) option passed to mv
wouldn't yield the desired result to flatten the directory structure and handle name conflicts. So it's simply replaced with --backup=t
(equivalent to --backup=numbered
). More documentation on the -b
(--backup
) option available at https://www.gnu.org/software/coreutils/manual/coreutils.html#Backup-options.
Resulting in:
find dir1/ -mindepth 2 -type f -exec mv -t dir1/ --backup=t '{}' +
Which yields:
dir1/
├── dir2
├── dir3
├── file
└── file.~1~
edited Jan 9 at 20:38
answered Jan 9 at 20:31
Yann EvesYann Eves
12
12
add a comment |
add a comment |
Thanks for contributing an answer to Unix & Linux Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f52814%2fflattening-a-nested-directory%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
askubuntu.com/questions/633945/…
– Ferroao
Dec 12 '17 at 14:55