Sign up ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

I want to enter every directory retuned by ls command and execute script.

I tried this (and many other things), but it just does not work

ls  | awk '{print $1" && pwd"}' | xargs cd

How to do it without for loop?

share|improve this question
Why specifically ls and not a for-loop? The for-loop would be the easier approach, and in addition it won't break on directories containing whitespace or quotes, like you'll get problems with when parsing ls output. –  geirha Nov 9 '11 at 15:57
See also: How to go to each directory and execute a command? at stackoverflow. –  kenorb Oct 21 '14 at 20:15

7 Answers 7

up vote 5 down vote accepted

If you can, use find as suggested in other answers, xargs is almost always to avoid.

But if you still want to use xargs, a possible alternative is the following:

printf '%s\0' */ | xargs -0 -L1 bash -c 'cd -- "$1" && pwd' _

Some notes:

  1. */ expands to the list of directories in the current folder, thanks to the trailing slash

  2. printf with \0 (null byte) separates the elements one for each line

  3. the option -L1 to xargs makes it to execute once for every input line and the optiont -0 makes it separate the input on the null byte: filenames can contain any character, the command doesn't break!

  4. bash removes the double quotes and pass it to the inline script as a single parameter, but cd should put double quotes again to interpret it as a single string; using -- makes the cd command robust against filenames that start with a hyphen

  5. to avoid the strange use of $0 as a parameter, is usual to put a first dummy argument _

share|improve this answer
I knew echo * but was not aware of */. And putting an underscore as the 1st argument is a neat trick. –  lgarzo Nov 9 '11 at 15:59
thx a lot, I'm learning bash and this is very helpful. –  UAdapter Nov 10 '11 at 9:40
@gniourf_gniourf: thank for editing and providing a more robust command. –  enzotib yesterday

Maybe take a look at using find with -exec?

share|improve this answer
find . -type d -exec bash -c 'cd "$0" && pwd' {} \;

Swap pwd for your script. And . for the root directory name, if it's not the "current" directory.

You have to wrap the exec clause in bash -c "..." because of the way -exec works. cd doesn't exist in its limited environment, but as you can see by running the above command, when you bring in bash to do the job, everything runs as predicted.

Edit: I'm not sure why 2011 Oli didn't think of -execdir but that's probably a faster solution:

find . -type d -execdir pwd \;
share|improve this answer
The reason cd alone do not work is because it is a shell builtin, nothing to do with the environment. –  enzotib Nov 9 '11 at 15:07
Nice work Oli. I added maxdepth here as mentioned before, also since it seems to imply current subdirectories i removed .: find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && pwd" \; –  Todd Partridge 'Gen2ly' May 29 '12 at 16:59

The find command

The find command is pretty handy. It can generate a list of files or directorise in or below a specified directory, and it can also execute a command on each item in that list of results. (Note: if you're using a multi-user system, make sure to read the security considerations section of the Findutils documentation for the find command.)

The options to the find command that we need are -type d which tells find to return the names of every directory within the specified path, and -exec command '{}' \; which tells find to run command on the results. For example:

find /media/music/flac -type d -exec ~/ '{}' \;

This tells find to return every directory in or below the path /media/music/flac and then run the script on each directory found. The '{}' is replaced by each directory name found, and gets passed as an argument to the script. The \; marks the end of the arguments list to the script. may be this will help u

share|improve this answer
No need to quote {}, and a -maxdepth 1 could be useful, if the OP do not want to recurse into subdirectories. –  enzotib Nov 9 '11 at 15:11
@enzotib I did not know about the -maxdepth 1, thx –  UAdapter Nov 9 '11 at 15:42

Just for curiosity I tried to take your example and make it work. There is no reason to use this technique instead of the find command.

Note: Thanks to enzotib for pointing it out, this does not work for directory names containing spaces or any other characters that make awk think the name consists of several fields.

To make your example work a few tweaks should be made. But at first see the code:

ls -l | grep ^d | awk '{print $NF}' | xargs -n 1 bash -c 'cd $0; ls'

The first two commands make sure that only directories are listed. Since ls long listing contains a d as the first character for directories, the grep command selects only these lines.

With awk only the last column is displayed in every line. NF is a built-in variable in awk holding the maximum number of fields. Thus printing $NF displays the last field.

Finally xargs needed to be tamed to run the specified script with only one parameters at a time. (I know this kind-of defeats its purpose.) Otherwise the script could not be run for every directory without a for loop.

And to work around the built-in cd barrier, we call bash with -c. Also note that $0 becomes the first parameter instead of $1.

share|improve this answer
Unfortunately, if you have directories names containing spaces, $NF gives only the last word of the name. This is one of the reason why people is suggested to not parse ls output. –  enzotib Nov 9 '11 at 15:15
This is a valid point and I do not see an easy workaround without creating a lengthy awk script. I was trying to demonstrate how the original thinking could work (and to convince the OP not to use it, because it is at least not elegant). Thank you for pointing it out, I'll update the answer. –  lgarzo Nov 9 '11 at 15:23
See my answer working with xargs. –  enzotib Nov 9 '11 at 15:43
thx a lot, I'm learning bash and this is very helpful. –  UAdapter Nov 10 '11 at 9:40

Other alternative:

for directory in *
  (cd $directory && awk '{print $1" && pwd"}')
share|improve this answer

You shouldn't parse ls in the first place.

You can use GNU find for that and its -execdir parameter, e.g.:

find . -type d -execdir realpath "{}" ';'

or more practical example:

find . -name .git -type d -execdir git pull -v ';'

and here is version with -exec:

find . -type d -print0 | xargs -0 -I% sh -c 'cd "%" && pwd && echo Do stuff'

For more examples, see: How to go to each directory and execute a command? at SO

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.