bash script - flatten directory structure

The name of the pictureThe name of the pictureThe name of the pictureClash 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







share|improve this question





















  • 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














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







share|improve this question





















  • 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












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







share|improve this question













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









share|improve this question












share|improve this question




share|improve this question








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
















  • 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










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.






share|improve this answer























  • 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










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',
convertImagesToLinks: false,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);








 

draft saved


draft discarded


















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






























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.






share|improve this answer























  • 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














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.






share|improve this answer























  • 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












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.






share|improve this answer















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.







share|improve this answer















share|improve this answer



share|improve this answer








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
















  • 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












 

draft saved


draft discarded


























 


draft saved


draft discarded














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













































































Popular posts from this blog

Peggy Mitchell

Palaiologos

The Forum (Inglewood, California)