for loop in folders with n character in their names

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP








up vote
9
down vote

favorite
2












I have some folders with n character it their names.



for example:



$ ls
''$'n''Test'


Thats refer to a folder with Test name and a empty line before its name.



So when I run some scripts like this, in its parent directory:



while IFS= read -r d; do 
rmdir $d
done < <(find * -type d)


It shows:



rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory


Because it runs twice, once on n and the another on Test, because the folder name has two lines.



So how can I solve this issue such that, script knows nTest is just one folder?







share|improve this question















  • 3




    You need to use find's -print0 directive, and the -d read option. See stackoverflow.com/a/40189667/7552
    – glenn jackman
    Jun 4 at 22:27






  • 1




    @glennjackman Please answer!
    – dessert
    Jun 4 at 22:27










  • @glennjackman Thanks for your reply but find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done command have this output rmdir: failed to remove 'Test': No such file or directory.
    – Tara S Volpe
    Jun 4 at 22:34






  • 5




    You must quote the variable : rmdir "$file"
    – glenn jackman
    Jun 4 at 22:40






  • 1




    @glennjackman Just post this as answer. It's a proper solution and besides comments are not the best place for that. Upvote already implied :)
    – Sergiy Kolodyazhnyy
    Jun 5 at 0:56














up vote
9
down vote

favorite
2












I have some folders with n character it their names.



for example:



$ ls
''$'n''Test'


Thats refer to a folder with Test name and a empty line before its name.



So when I run some scripts like this, in its parent directory:



while IFS= read -r d; do 
rmdir $d
done < <(find * -type d)


It shows:



rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory


Because it runs twice, once on n and the another on Test, because the folder name has two lines.



So how can I solve this issue such that, script knows nTest is just one folder?







share|improve this question















  • 3




    You need to use find's -print0 directive, and the -d read option. See stackoverflow.com/a/40189667/7552
    – glenn jackman
    Jun 4 at 22:27






  • 1




    @glennjackman Please answer!
    – dessert
    Jun 4 at 22:27










  • @glennjackman Thanks for your reply but find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done command have this output rmdir: failed to remove 'Test': No such file or directory.
    – Tara S Volpe
    Jun 4 at 22:34






  • 5




    You must quote the variable : rmdir "$file"
    – glenn jackman
    Jun 4 at 22:40






  • 1




    @glennjackman Just post this as answer. It's a proper solution and besides comments are not the best place for that. Upvote already implied :)
    – Sergiy Kolodyazhnyy
    Jun 5 at 0:56












up vote
9
down vote

favorite
2









up vote
9
down vote

favorite
2






2





I have some folders with n character it their names.



for example:



$ ls
''$'n''Test'


Thats refer to a folder with Test name and a empty line before its name.



So when I run some scripts like this, in its parent directory:



while IFS= read -r d; do 
rmdir $d
done < <(find * -type d)


It shows:



rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory


Because it runs twice, once on n and the another on Test, because the folder name has two lines.



So how can I solve this issue such that, script knows nTest is just one folder?







share|improve this question











I have some folders with n character it their names.



for example:



$ ls
''$'n''Test'


Thats refer to a folder with Test name and a empty line before its name.



So when I run some scripts like this, in its parent directory:



while IFS= read -r d; do 
rmdir $d
done < <(find * -type d)


It shows:



rmdir: failed to remove '': No such file or directory
rmdir: failed to remove 'Test': No such file or directory


Because it runs twice, once on n and the another on Test, because the folder name has two lines.



So how can I solve this issue such that, script knows nTest is just one folder?









share|improve this question










share|improve this question




share|improve this question









asked Jun 4 at 22:21









Tara S Volpe

18017




18017







  • 3




    You need to use find's -print0 directive, and the -d read option. See stackoverflow.com/a/40189667/7552
    – glenn jackman
    Jun 4 at 22:27






  • 1




    @glennjackman Please answer!
    – dessert
    Jun 4 at 22:27










  • @glennjackman Thanks for your reply but find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done command have this output rmdir: failed to remove 'Test': No such file or directory.
    – Tara S Volpe
    Jun 4 at 22:34






  • 5




    You must quote the variable : rmdir "$file"
    – glenn jackman
    Jun 4 at 22:40






  • 1




    @glennjackman Just post this as answer. It's a proper solution and besides comments are not the best place for that. Upvote already implied :)
    – Sergiy Kolodyazhnyy
    Jun 5 at 0:56












  • 3




    You need to use find's -print0 directive, and the -d read option. See stackoverflow.com/a/40189667/7552
    – glenn jackman
    Jun 4 at 22:27






  • 1




    @glennjackman Please answer!
    – dessert
    Jun 4 at 22:27










  • @glennjackman Thanks for your reply but find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done command have this output rmdir: failed to remove 'Test': No such file or directory.
    – Tara S Volpe
    Jun 4 at 22:34






  • 5




    You must quote the variable : rmdir "$file"
    – glenn jackman
    Jun 4 at 22:40






  • 1




    @glennjackman Just post this as answer. It's a proper solution and besides comments are not the best place for that. Upvote already implied :)
    – Sergiy Kolodyazhnyy
    Jun 5 at 0:56







3




3




You need to use find's -print0 directive, and the -d read option. See stackoverflow.com/a/40189667/7552
– glenn jackman
Jun 4 at 22:27




You need to use find's -print0 directive, and the -d read option. See stackoverflow.com/a/40189667/7552
– glenn jackman
Jun 4 at 22:27




1




1




@glennjackman Please answer!
– dessert
Jun 4 at 22:27




@glennjackman Please answer!
– dessert
Jun 4 at 22:27












@glennjackman Thanks for your reply but find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done command have this output rmdir: failed to remove 'Test': No such file or directory.
– Tara S Volpe
Jun 4 at 22:34




@glennjackman Thanks for your reply but find * -type d -print0 | while IFS= read -d '' file ; do rmdir $file ; done command have this output rmdir: failed to remove 'Test': No such file or directory.
– Tara S Volpe
Jun 4 at 22:34




5




5




You must quote the variable : rmdir "$file"
– glenn jackman
Jun 4 at 22:40




You must quote the variable : rmdir "$file"
– glenn jackman
Jun 4 at 22:40




1




1




@glennjackman Just post this as answer. It's a proper solution and besides comments are not the best place for that. Upvote already implied :)
– Sergiy Kolodyazhnyy
Jun 5 at 0:56




@glennjackman Just post this as answer. It's a proper solution and besides comments are not the best place for that. Upvote already implied :)
– Sergiy Kolodyazhnyy
Jun 5 at 0:56










3 Answers
3






active

oldest

votes

















up vote
12
down vote



accepted










You've only single command there, so it's sufficient to call find with -exec flag calling rmdir:



find -depth -type d -exec rmdir ;


Or use the -delete option as in find -type d -delete, but it won't work with non-empty directories. For that you will also need -empty flag. Note also, -delete implies -depth so that may be skipped. Thus another viable alternative that keeps everything as one process:



find -type d -empty -delete


If the directory not empty, use rm -rf ;. To isolate only directories with n in filename we can combine bash's ANSI-C quoting $'...' with -name opption:



find -type d -name $'*n*' -empty -delete


POSIX-ly, we could handle it this way:



find -depth -type d -name "$(printf '*n*' )" -exec rmdir ;


It is worth mentioning that if your goal is removal of directories, then -delete is sufficient, however if you want to execute a command on directory then -exec is most appropriate.



See also



  • How to delete directories based on find output?

  • find -delete does not delete non-empty directories





share|improve this answer



















  • 2




    … use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
    – dessert
    Jun 4 at 22:41







  • 3




    @dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
    – Sergiy Kolodyazhnyy
    Jun 4 at 22:47






  • 6




    Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
    – Byte Commander
    Jun 4 at 22:50






  • 2




    This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
    – Peter Cordes
    Jun 5 at 1:01







  • 2




    find -type d -empty -delete (-delete implies -depth).
    – Kevin
    Jun 5 at 2:51

















up vote
10
down vote













You could use shell globs instead of find:



for d in */ ; do 
rmdir "$d"
done


The shell glob */ matches all folders in the current directory. This for-loop construction takes care of correct word splitting automatically.



Note that depending on your shell options, this might ignore hidden folders (name starting with a .). That behaviour can be changed to match all files for the current session using the command shopt -s dotglob.



Also don't forget to always quote your variables.






share|improve this answer





















  • the glob will only find files/directories in the current directory, not recursively like find does
    – ilkkachu
    Jun 5 at 9:54






  • 1




    You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
    – Byte Commander
    Jun 5 at 10:26

















up vote
6
down vote













Both answers written so far call rmdir once per directory, but as rmdir can take multiple arguments I wonder: Isn’t there a more efficient way?



One could simply do



rmdir */


and that’s definitely the easiest and most efficient way, but it may throw an error in the case of many directories (see What is the maximum length of command line arguments in gnome-terminal?). If you want this approach to work recursively, enable the globstar shell option with shopt -s globstar and use **/*/ instead of */.



With GNU find (and if we don’t just want to use -delete), we could do



find -depth -type d -exec rmdir +


which builts the command line “in much the same way that xargs builds its command lines” (man find). Substitute -depth for -maxdepth 1 if you don’t want it to work recursively.



A third and IMO brilliant way is explained by steeldriver in this answer:



printf '%s' */ | xargs -0 rmdir


This uses the shell builtin printf to build a zero-delimited argument list, this list is then piped to xargs which calls rmdir exactly as often as necessary. You can make it work recursively with shopt -s globstar and **/*/ instead of */ as above.






share|improve this answer



















  • 2




    find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
    – Peter Cordes
    Jun 5 at 9:08







  • 1




    Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
    – Peter Cordes
    Jun 5 at 9:15











Your Answer







StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "89"
;
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: true,
noModals: false,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
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%2faskubuntu.com%2fquestions%2f1043640%2ffor-loop-in-folders-with-n-character-in-their-names%23new-answer', 'question_page');

);

Post as a guest






























3 Answers
3






active

oldest

votes








3 Answers
3






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
12
down vote



accepted










You've only single command there, so it's sufficient to call find with -exec flag calling rmdir:



find -depth -type d -exec rmdir ;


Or use the -delete option as in find -type d -delete, but it won't work with non-empty directories. For that you will also need -empty flag. Note also, -delete implies -depth so that may be skipped. Thus another viable alternative that keeps everything as one process:



find -type d -empty -delete


If the directory not empty, use rm -rf ;. To isolate only directories with n in filename we can combine bash's ANSI-C quoting $'...' with -name opption:



find -type d -name $'*n*' -empty -delete


POSIX-ly, we could handle it this way:



find -depth -type d -name "$(printf '*n*' )" -exec rmdir ;


It is worth mentioning that if your goal is removal of directories, then -delete is sufficient, however if you want to execute a command on directory then -exec is most appropriate.



See also



  • How to delete directories based on find output?

  • find -delete does not delete non-empty directories





share|improve this answer



















  • 2




    … use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
    – dessert
    Jun 4 at 22:41







  • 3




    @dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
    – Sergiy Kolodyazhnyy
    Jun 4 at 22:47






  • 6




    Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
    – Byte Commander
    Jun 4 at 22:50






  • 2




    This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
    – Peter Cordes
    Jun 5 at 1:01







  • 2




    find -type d -empty -delete (-delete implies -depth).
    – Kevin
    Jun 5 at 2:51














up vote
12
down vote



accepted










You've only single command there, so it's sufficient to call find with -exec flag calling rmdir:



find -depth -type d -exec rmdir ;


Or use the -delete option as in find -type d -delete, but it won't work with non-empty directories. For that you will also need -empty flag. Note also, -delete implies -depth so that may be skipped. Thus another viable alternative that keeps everything as one process:



find -type d -empty -delete


If the directory not empty, use rm -rf ;. To isolate only directories with n in filename we can combine bash's ANSI-C quoting $'...' with -name opption:



find -type d -name $'*n*' -empty -delete


POSIX-ly, we could handle it this way:



find -depth -type d -name "$(printf '*n*' )" -exec rmdir ;


It is worth mentioning that if your goal is removal of directories, then -delete is sufficient, however if you want to execute a command on directory then -exec is most appropriate.



See also



  • How to delete directories based on find output?

  • find -delete does not delete non-empty directories





share|improve this answer



















  • 2




    … use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
    – dessert
    Jun 4 at 22:41







  • 3




    @dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
    – Sergiy Kolodyazhnyy
    Jun 4 at 22:47






  • 6




    Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
    – Byte Commander
    Jun 4 at 22:50






  • 2




    This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
    – Peter Cordes
    Jun 5 at 1:01







  • 2




    find -type d -empty -delete (-delete implies -depth).
    – Kevin
    Jun 5 at 2:51












up vote
12
down vote



accepted







up vote
12
down vote



accepted






You've only single command there, so it's sufficient to call find with -exec flag calling rmdir:



find -depth -type d -exec rmdir ;


Or use the -delete option as in find -type d -delete, but it won't work with non-empty directories. For that you will also need -empty flag. Note also, -delete implies -depth so that may be skipped. Thus another viable alternative that keeps everything as one process:



find -type d -empty -delete


If the directory not empty, use rm -rf ;. To isolate only directories with n in filename we can combine bash's ANSI-C quoting $'...' with -name opption:



find -type d -name $'*n*' -empty -delete


POSIX-ly, we could handle it this way:



find -depth -type d -name "$(printf '*n*' )" -exec rmdir ;


It is worth mentioning that if your goal is removal of directories, then -delete is sufficient, however if you want to execute a command on directory then -exec is most appropriate.



See also



  • How to delete directories based on find output?

  • find -delete does not delete non-empty directories





share|improve this answer















You've only single command there, so it's sufficient to call find with -exec flag calling rmdir:



find -depth -type d -exec rmdir ;


Or use the -delete option as in find -type d -delete, but it won't work with non-empty directories. For that you will also need -empty flag. Note also, -delete implies -depth so that may be skipped. Thus another viable alternative that keeps everything as one process:



find -type d -empty -delete


If the directory not empty, use rm -rf ;. To isolate only directories with n in filename we can combine bash's ANSI-C quoting $'...' with -name opption:



find -type d -name $'*n*' -empty -delete


POSIX-ly, we could handle it this way:



find -depth -type d -name "$(printf '*n*' )" -exec rmdir ;


It is worth mentioning that if your goal is removal of directories, then -delete is sufficient, however if you want to execute a command on directory then -exec is most appropriate.



See also



  • How to delete directories based on find output?

  • find -delete does not delete non-empty directories






share|improve this answer















share|improve this answer



share|improve this answer








edited Jun 5 at 17:49


























answered Jun 4 at 22:40









Sergiy Kolodyazhnyy

63.8k9127273




63.8k9127273







  • 2




    … use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
    – dessert
    Jun 4 at 22:41







  • 3




    @dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
    – Sergiy Kolodyazhnyy
    Jun 4 at 22:47






  • 6




    Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
    – Byte Commander
    Jun 4 at 22:50






  • 2




    This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
    – Peter Cordes
    Jun 5 at 1:01







  • 2




    find -type d -empty -delete (-delete implies -depth).
    – Kevin
    Jun 5 at 2:51












  • 2




    … use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
    – dessert
    Jun 4 at 22:41







  • 3




    @dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
    – Sergiy Kolodyazhnyy
    Jun 4 at 22:47






  • 6




    Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
    – Byte Commander
    Jun 4 at 22:50






  • 2




    This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
    – Peter Cordes
    Jun 5 at 1:01







  • 2




    find -type d -empty -delete (-delete implies -depth).
    – Kevin
    Jun 5 at 2:51







2




2




… use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
– dessert
Jun 4 at 22:41





… use rm -rf with care. ;P Doesn’t find have a -delete option btw? It deletes empty directories and throws errors for non-empty ones like rmdir – might be less expensive.
– dessert
Jun 4 at 22:41





3




3




@dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
– Sergiy Kolodyazhnyy
Jun 4 at 22:47




@dessert It does and I added that in, but -delete won't remove non-empty directories. Hence, the careful use of rm -rf
– Sergiy Kolodyazhnyy
Jun 4 at 22:47




6




6




Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
– Byte Commander
Jun 4 at 22:50




Always dry-run such find commands without any destructive payload (i.e. remove the -delete or -exec whatever ;) to check if the list of affected files is actually correct and does not contain stuff that should not get deleted...
– Byte Commander
Jun 4 at 22:50




2




2




This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
– Peter Cordes
Jun 5 at 1:01





This is askubuntu.com so we can assume GNU find. Use -exec rmdir + to batch multiple args onto one rmdir command line. And BTW "but it won't work with non-empty directories." applies to rmdir as well, so that's not actually a difference from -delete. It's a difference from rm -r.
– Peter Cordes
Jun 5 at 1:01





2




2




find -type d -empty -delete (-delete implies -depth).
– Kevin
Jun 5 at 2:51




find -type d -empty -delete (-delete implies -depth).
– Kevin
Jun 5 at 2:51












up vote
10
down vote













You could use shell globs instead of find:



for d in */ ; do 
rmdir "$d"
done


The shell glob */ matches all folders in the current directory. This for-loop construction takes care of correct word splitting automatically.



Note that depending on your shell options, this might ignore hidden folders (name starting with a .). That behaviour can be changed to match all files for the current session using the command shopt -s dotglob.



Also don't forget to always quote your variables.






share|improve this answer





















  • the glob will only find files/directories in the current directory, not recursively like find does
    – ilkkachu
    Jun 5 at 9:54






  • 1




    You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
    – Byte Commander
    Jun 5 at 10:26














up vote
10
down vote













You could use shell globs instead of find:



for d in */ ; do 
rmdir "$d"
done


The shell glob */ matches all folders in the current directory. This for-loop construction takes care of correct word splitting automatically.



Note that depending on your shell options, this might ignore hidden folders (name starting with a .). That behaviour can be changed to match all files for the current session using the command shopt -s dotglob.



Also don't forget to always quote your variables.






share|improve this answer





















  • the glob will only find files/directories in the current directory, not recursively like find does
    – ilkkachu
    Jun 5 at 9:54






  • 1




    You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
    – Byte Commander
    Jun 5 at 10:26












up vote
10
down vote










up vote
10
down vote









You could use shell globs instead of find:



for d in */ ; do 
rmdir "$d"
done


The shell glob */ matches all folders in the current directory. This for-loop construction takes care of correct word splitting automatically.



Note that depending on your shell options, this might ignore hidden folders (name starting with a .). That behaviour can be changed to match all files for the current session using the command shopt -s dotglob.



Also don't forget to always quote your variables.






share|improve this answer













You could use shell globs instead of find:



for d in */ ; do 
rmdir "$d"
done


The shell glob */ matches all folders in the current directory. This for-loop construction takes care of correct word splitting automatically.



Note that depending on your shell options, this might ignore hidden folders (name starting with a .). That behaviour can be changed to match all files for the current session using the command shopt -s dotglob.



Also don't forget to always quote your variables.







share|improve this answer













share|improve this answer



share|improve this answer











answered Jun 4 at 22:36









Byte Commander

58k26155263




58k26155263











  • the glob will only find files/directories in the current directory, not recursively like find does
    – ilkkachu
    Jun 5 at 9:54






  • 1




    You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
    – Byte Commander
    Jun 5 at 10:26
















  • the glob will only find files/directories in the current directory, not recursively like find does
    – ilkkachu
    Jun 5 at 9:54






  • 1




    You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
    – Byte Commander
    Jun 5 at 10:26















the glob will only find files/directories in the current directory, not recursively like find does
– ilkkachu
Jun 5 at 9:54




the glob will only find files/directories in the current directory, not recursively like find does
– ilkkachu
Jun 5 at 9:54




1




1




You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
– Byte Commander
Jun 5 at 10:26




You are right @ilkkachu. That could be changed by enabling the globstar shell option shopt -s globstar and using a **/*/ glob instead.
– Byte Commander
Jun 5 at 10:26










up vote
6
down vote













Both answers written so far call rmdir once per directory, but as rmdir can take multiple arguments I wonder: Isn’t there a more efficient way?



One could simply do



rmdir */


and that’s definitely the easiest and most efficient way, but it may throw an error in the case of many directories (see What is the maximum length of command line arguments in gnome-terminal?). If you want this approach to work recursively, enable the globstar shell option with shopt -s globstar and use **/*/ instead of */.



With GNU find (and if we don’t just want to use -delete), we could do



find -depth -type d -exec rmdir +


which builts the command line “in much the same way that xargs builds its command lines” (man find). Substitute -depth for -maxdepth 1 if you don’t want it to work recursively.



A third and IMO brilliant way is explained by steeldriver in this answer:



printf '%s' */ | xargs -0 rmdir


This uses the shell builtin printf to build a zero-delimited argument list, this list is then piped to xargs which calls rmdir exactly as often as necessary. You can make it work recursively with shopt -s globstar and **/*/ instead of */ as above.






share|improve this answer



















  • 2




    find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
    – Peter Cordes
    Jun 5 at 9:08







  • 1




    Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
    – Peter Cordes
    Jun 5 at 9:15















up vote
6
down vote













Both answers written so far call rmdir once per directory, but as rmdir can take multiple arguments I wonder: Isn’t there a more efficient way?



One could simply do



rmdir */


and that’s definitely the easiest and most efficient way, but it may throw an error in the case of many directories (see What is the maximum length of command line arguments in gnome-terminal?). If you want this approach to work recursively, enable the globstar shell option with shopt -s globstar and use **/*/ instead of */.



With GNU find (and if we don’t just want to use -delete), we could do



find -depth -type d -exec rmdir +


which builts the command line “in much the same way that xargs builds its command lines” (man find). Substitute -depth for -maxdepth 1 if you don’t want it to work recursively.



A third and IMO brilliant way is explained by steeldriver in this answer:



printf '%s' */ | xargs -0 rmdir


This uses the shell builtin printf to build a zero-delimited argument list, this list is then piped to xargs which calls rmdir exactly as often as necessary. You can make it work recursively with shopt -s globstar and **/*/ instead of */ as above.






share|improve this answer



















  • 2




    find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
    – Peter Cordes
    Jun 5 at 9:08







  • 1




    Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
    – Peter Cordes
    Jun 5 at 9:15













up vote
6
down vote










up vote
6
down vote









Both answers written so far call rmdir once per directory, but as rmdir can take multiple arguments I wonder: Isn’t there a more efficient way?



One could simply do



rmdir */


and that’s definitely the easiest and most efficient way, but it may throw an error in the case of many directories (see What is the maximum length of command line arguments in gnome-terminal?). If you want this approach to work recursively, enable the globstar shell option with shopt -s globstar and use **/*/ instead of */.



With GNU find (and if we don’t just want to use -delete), we could do



find -depth -type d -exec rmdir +


which builts the command line “in much the same way that xargs builds its command lines” (man find). Substitute -depth for -maxdepth 1 if you don’t want it to work recursively.



A third and IMO brilliant way is explained by steeldriver in this answer:



printf '%s' */ | xargs -0 rmdir


This uses the shell builtin printf to build a zero-delimited argument list, this list is then piped to xargs which calls rmdir exactly as often as necessary. You can make it work recursively with shopt -s globstar and **/*/ instead of */ as above.






share|improve this answer















Both answers written so far call rmdir once per directory, but as rmdir can take multiple arguments I wonder: Isn’t there a more efficient way?



One could simply do



rmdir */


and that’s definitely the easiest and most efficient way, but it may throw an error in the case of many directories (see What is the maximum length of command line arguments in gnome-terminal?). If you want this approach to work recursively, enable the globstar shell option with shopt -s globstar and use **/*/ instead of */.



With GNU find (and if we don’t just want to use -delete), we could do



find -depth -type d -exec rmdir +


which builts the command line “in much the same way that xargs builds its command lines” (man find). Substitute -depth for -maxdepth 1 if you don’t want it to work recursively.



A third and IMO brilliant way is explained by steeldriver in this answer:



printf '%s' */ | xargs -0 rmdir


This uses the shell builtin printf to build a zero-delimited argument list, this list is then piped to xargs which calls rmdir exactly as often as necessary. You can make it work recursively with shopt -s globstar and **/*/ instead of */ as above.







share|improve this answer















share|improve this answer



share|improve this answer








edited Jun 6 at 22:09


























answered Jun 5 at 8:33









dessert

19.4k55494




19.4k55494







  • 2




    find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
    – Peter Cordes
    Jun 5 at 9:08







  • 1




    Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
    – Peter Cordes
    Jun 5 at 9:15













  • 2




    find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
    – Peter Cordes
    Jun 5 at 9:08







  • 1




    Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
    – Peter Cordes
    Jun 5 at 9:15








2




2




find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
– Peter Cordes
Jun 5 at 9:08





find is recursive, but the OP's loop isn't. To replicate that behaviour, use find -maxdepth 1 -type d -exec rmdir +. (-depth is redundant in that case.) Neat trick with printf to emulate find -print0, I hadn't seen that before.
– Peter Cordes
Jun 5 at 9:08





1




1




Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
– Peter Cordes
Jun 5 at 9:15





Oh! I saw the ls and the while loop, I missed that they were redirecting from a process substitution with find instead of piping ls into the loop and just not showing it for some reason. That find * is really buried. Yes it's recursive, and will fail if there are too many directory entries in the directory, including non-directories because it doesn't use */. find . would be much better, because find is faster at stating than bash's glob expansion.
– Peter Cordes
Jun 5 at 9:15













 

draft saved


draft discarded


























 


draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2faskubuntu.com%2fquestions%2f1043640%2ffor-loop-in-folders-with-n-character-in-their-names%23new-answer', 'question_page');

);

Post as a guest













































































Popular posts from this blog

pylint3 and pip3 broken

Missing snmpget and snmpwalk

How to enroll fingerprints to Ubuntu 17.10 with VFS491