21

In a bash script, I want to iterate over all the directories in the present working directory and do stuff to them. They may contain special symbols, especially whitespace. How can I do that? I have:

for dir in $( ls -l ./)
do
    if [ -d ./"$dir" ]

but this skips my directories with whitespace in their name. Any help is appreciated.

0

3 Answers 3

49

Give this a try:

for dir in */
Sign up to request clarification or add additional context in comments.

7 Comments

this does it, but why? */ is a wildcard for all directories?
Wow, that actually works, even on directories with spaces. So, bash must implicitly quote the values when it expands the wildcard? I love it.
@JakeVA: Yes, exactly. Note that it won't include hidden directories unless you set shopt -s dotglob. If the current directory may have no subdirectories, you should also set shopt -s nullglob (set it just in case).
@Air: shopt -s globstar; for dir in **/ in Bash 4 will recurse.
@Sigur: for dir in /some/dir/*/ or recursively shopt -s globstar; for dir in /some/dir/*/. Any directory spec will do, the magic is in adding the final slash after the glob.
|
16

Take your pick of solutions:

http://www.cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html

The general idea is to change the default seperator (IFS).

#!/bin/bash
SAVEIFS=$IFS
IFS=$(echo -en "\n\b")
for f in *
do
  echo "$f"
done
IFS=$SAVEIFS

2 Comments

I neglected to mention this in my question, but I tried that. I think the missing piece was iterating over * or */ rather than the results of ls
I found my solution here, using find . -print0 | while read -d $'\0' file to set up a do loop with the variable file.
2

There are multiple ways. Here is something that is very fast:

find /your/dir -type d -print0 | xargs -0 echo

This will scan /your/dir recursively for directories and will pass all paths to the command "echo" (exchange to your need). It may call echo multiple time, but it will try to pass as many directory names as the console allows at once. This is extremely fast because few processes need to be started. But it works only on programs that can take an arbitrary amount of values as options. -print0 tells find to seperate file paths using a zero byte (and -0 tells xargs to read arguments seperated by zero byte) If you don't have the later one, you can do this:

find /your/dir -type d -print0 | xargs -0 -n 1 echo

or

find /your/dir -type d -print0 --exec echo '{}' ';'

The option -n 1 will tell xargs not to pass more arguments than one at the same time to your program. If you don't want find to scan recursively you can specify the depth option to disable recursion (don't know the syntax by heart though).

Though if that's usable in your particular script is another question ;-).

1 Comment

Note that xargs has additional tools that come in handy here, like -J <placeholder>. Example: xargs -0 -J % mv % ~/some_other_folder

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.