bash script - flatten directory structure

Clash Royale CLAN TAG#URR8PPP
up vote
0
down vote
favorite
I am looking for a shell script that would flatten a given directory structure but ONLY if there is only 1 subfolder in that directory. For instance: the script would flatten this folder:
/folder
/subfolder
file1
file2
into:
/folder
file1
file2
but would skip (do nothing) this folder
/folder
/subfolder1
/subfolder2
Thank you so much in advance.
Steve
bash shell-script
add a comment |Â
up vote
0
down vote
favorite
I am looking for a shell script that would flatten a given directory structure but ONLY if there is only 1 subfolder in that directory. For instance: the script would flatten this folder:
/folder
/subfolder
file1
file2
into:
/folder
file1
file2
but would skip (do nothing) this folder
/folder
/subfolder1
/subfolder2
Thank you so much in advance.
Steve
bash shell-script
I've fixed the markup and formatting of the text of the question. Please modify if I got it wrong.
â Kusalananda
Jun 22 at 12:51
This would involve rebuilding relative symlinks, I gather.
â Tomasz
Jun 22 at 12:56
add a comment |Â
up vote
0
down vote
favorite
up vote
0
down vote
favorite
I am looking for a shell script that would flatten a given directory structure but ONLY if there is only 1 subfolder in that directory. For instance: the script would flatten this folder:
/folder
/subfolder
file1
file2
into:
/folder
file1
file2
but would skip (do nothing) this folder
/folder
/subfolder1
/subfolder2
Thank you so much in advance.
Steve
bash shell-script
I am looking for a shell script that would flatten a given directory structure but ONLY if there is only 1 subfolder in that directory. For instance: the script would flatten this folder:
/folder
/subfolder
file1
file2
into:
/folder
file1
file2
but would skip (do nothing) this folder
/folder
/subfolder1
/subfolder2
Thank you so much in advance.
Steve
bash shell-script
edited Jun 22 at 13:15
Kusalananda
101k13199312
101k13199312
asked Jun 22 at 12:48
Steven D
11
11
I've fixed the markup and formatting of the text of the question. Please modify if I got it wrong.
â Kusalananda
Jun 22 at 12:51
This would involve rebuilding relative symlinks, I gather.
â Tomasz
Jun 22 at 12:56
add a comment |Â
I've fixed the markup and formatting of the text of the question. Please modify if I got it wrong.
â Kusalananda
Jun 22 at 12:51
This would involve rebuilding relative symlinks, I gather.
â Tomasz
Jun 22 at 12:56
I've fixed the markup and formatting of the text of the question. Please modify if I got it wrong.
â Kusalananda
Jun 22 at 12:51
I've fixed the markup and formatting of the text of the question. Please modify if I got it wrong.
â Kusalananda
Jun 22 at 12:51
This would involve rebuilding relative symlinks, I gather.
â Tomasz
Jun 22 at 12:56
This would involve rebuilding relative symlinks, I gather.
â Tomasz
Jun 22 at 12:56
add a comment |Â
1 Answer
1
active
oldest
votes
up vote
1
down vote
A somewhat naive approach:
#!/bin/sh
for dir do
# get list of directories under the directory $dir
set -- "$dir"/*/
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#" -gt 1 ] || [ ! -d "$1" ]; then
continue
fi
# the pathname of the subdirectory is now in $1
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "$1"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$1"
done
Using bash:
#!/bin/bash
for dir do
# get list of directories under the directory $dir
subdirs=( "$dir"/*/ )
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#subdirs[@]" -gt 1 ] || [ ! -d "$subdirs[0]" ]; then
continue
fi
# the pathname of the subdirectory is now in $subdirs[0]
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "subdirs[0]"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$subdirs[0]"
done
Both scripts would be run as
$ ./script.sh dir1 dir2 dir3
or
$ ./script.sh */
to run it across all directories in the current directory.
Apart from the caveats in the code, this would also fail to relink symbolic links. To do that, you would have to go through all possible locations in the filesystem and look for links pointing into the subdirectory under /folder and recreate them so that they point to the correct new place. I will not write the code far that here.
Also, no check is made when moving things out of the subdirectory to make sure that there are no entries with the same names already existing under /folder.
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let/folder(in your question) be dynamic?
â Kusalananda
Jun 22 at 15:25
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
 |Â
show 3 more comments
1 Answer
1
active
oldest
votes
1 Answer
1
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
1
down vote
A somewhat naive approach:
#!/bin/sh
for dir do
# get list of directories under the directory $dir
set -- "$dir"/*/
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#" -gt 1 ] || [ ! -d "$1" ]; then
continue
fi
# the pathname of the subdirectory is now in $1
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "$1"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$1"
done
Using bash:
#!/bin/bash
for dir do
# get list of directories under the directory $dir
subdirs=( "$dir"/*/ )
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#subdirs[@]" -gt 1 ] || [ ! -d "$subdirs[0]" ]; then
continue
fi
# the pathname of the subdirectory is now in $subdirs[0]
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "subdirs[0]"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$subdirs[0]"
done
Both scripts would be run as
$ ./script.sh dir1 dir2 dir3
or
$ ./script.sh */
to run it across all directories in the current directory.
Apart from the caveats in the code, this would also fail to relink symbolic links. To do that, you would have to go through all possible locations in the filesystem and look for links pointing into the subdirectory under /folder and recreate them so that they point to the correct new place. I will not write the code far that here.
Also, no check is made when moving things out of the subdirectory to make sure that there are no entries with the same names already existing under /folder.
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let/folder(in your question) be dynamic?
â Kusalananda
Jun 22 at 15:25
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
 |Â
show 3 more comments
up vote
1
down vote
A somewhat naive approach:
#!/bin/sh
for dir do
# get list of directories under the directory $dir
set -- "$dir"/*/
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#" -gt 1 ] || [ ! -d "$1" ]; then
continue
fi
# the pathname of the subdirectory is now in $1
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "$1"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$1"
done
Using bash:
#!/bin/bash
for dir do
# get list of directories under the directory $dir
subdirs=( "$dir"/*/ )
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#subdirs[@]" -gt 1 ] || [ ! -d "$subdirs[0]" ]; then
continue
fi
# the pathname of the subdirectory is now in $subdirs[0]
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "subdirs[0]"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$subdirs[0]"
done
Both scripts would be run as
$ ./script.sh dir1 dir2 dir3
or
$ ./script.sh */
to run it across all directories in the current directory.
Apart from the caveats in the code, this would also fail to relink symbolic links. To do that, you would have to go through all possible locations in the filesystem and look for links pointing into the subdirectory under /folder and recreate them so that they point to the correct new place. I will not write the code far that here.
Also, no check is made when moving things out of the subdirectory to make sure that there are no entries with the same names already existing under /folder.
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let/folder(in your question) be dynamic?
â Kusalananda
Jun 22 at 15:25
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
 |Â
show 3 more comments
up vote
1
down vote
up vote
1
down vote
A somewhat naive approach:
#!/bin/sh
for dir do
# get list of directories under the directory $dir
set -- "$dir"/*/
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#" -gt 1 ] || [ ! -d "$1" ]; then
continue
fi
# the pathname of the subdirectory is now in $1
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "$1"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$1"
done
Using bash:
#!/bin/bash
for dir do
# get list of directories under the directory $dir
subdirs=( "$dir"/*/ )
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#subdirs[@]" -gt 1 ] || [ ! -d "$subdirs[0]" ]; then
continue
fi
# the pathname of the subdirectory is now in $subdirs[0]
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "subdirs[0]"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$subdirs[0]"
done
Both scripts would be run as
$ ./script.sh dir1 dir2 dir3
or
$ ./script.sh */
to run it across all directories in the current directory.
Apart from the caveats in the code, this would also fail to relink symbolic links. To do that, you would have to go through all possible locations in the filesystem and look for links pointing into the subdirectory under /folder and recreate them so that they point to the correct new place. I will not write the code far that here.
Also, no check is made when moving things out of the subdirectory to make sure that there are no entries with the same names already existing under /folder.
A somewhat naive approach:
#!/bin/sh
for dir do
# get list of directories under the directory $dir
set -- "$dir"/*/
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#" -gt 1 ] || [ ! -d "$1" ]; then
continue
fi
# the pathname of the subdirectory is now in $1
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "$1"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$1"
done
Using bash:
#!/bin/bash
for dir do
# get list of directories under the directory $dir
subdirs=( "$dir"/*/ )
# if there are more than one, continue with the next directory
# also continue if we didn't match anything useful
if [ "$#subdirs[@]" -gt 1 ] || [ ! -d "$subdirs[0]" ]; then
continue
fi
# the pathname of the subdirectory is now in $subdirs[0]
# move everything from beneath the subdirectory to $dir
# (this will skip hidden files)
mv "subdirs[0]"/* "$dir"
# remove the subdirectory
# (this will fail if there were hidden files)
rmdir "$subdirs[0]"
done
Both scripts would be run as
$ ./script.sh dir1 dir2 dir3
or
$ ./script.sh */
to run it across all directories in the current directory.
Apart from the caveats in the code, this would also fail to relink symbolic links. To do that, you would have to go through all possible locations in the filesystem and look for links pointing into the subdirectory under /folder and recreate them so that they point to the correct new place. I will not write the code far that here.
Also, no check is made when moving things out of the subdirectory to make sure that there are no entries with the same names already existing under /folder.
edited Jun 23 at 15:53
answered Jun 22 at 13:01
Kusalananda
101k13199312
101k13199312
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let/folder(in your question) be dynamic?
â Kusalananda
Jun 22 at 15:25
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
 |Â
show 3 more comments
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let/folder(in your question) be dynamic?
â Kusalananda
Jun 22 at 15:25
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
Thank you. Ill give it a try. How about if I wanted to check all folders in any given directory in a loop like in "for every folder in directory do ...."?
â Steven D
Jun 22 at 15:04
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD You wanted to do this only when the directory contained a single subdirectory, right? A loop would not allow you to count the number of subdirectories.
â Kusalananda
Jun 22 at 15:09
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let
/folder (in your question) be dynamic?â Kusalananda
Jun 22 at 15:25
@StevenD Or I might have misunderstood you... Do you mean that you want to iterate over a number of folders, and flatten each individually if they contained only one directory? I.e. let
/folder (in your question) be dynamic?â Kusalananda
Jun 22 at 15:25
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
Kusalanda. Exactly. Flatten each folder (within a directory) that contains only one subfolder. Doable?
â Steven D
Jun 23 at 15:47
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
@StevenD See updated answer. Basically we do the operation on each directory listed on the command line of the script.
â Kusalananda
Jun 23 at 15:54
 |Â
show 3 more comments
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
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2funix.stackexchange.com%2fquestions%2f451305%2fbash-script-flatten-directory-structure%23new-answer', 'question_page');
);
Post as a guest
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
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
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
I've fixed the markup and formatting of the text of the question. Please modify if I got it wrong.
â Kusalananda
Jun 22 at 12:51
This would involve rebuilding relative symlinks, I gather.
â Tomasz
Jun 22 at 12:56