1

I have a folder which got several folders. I get list of all folders using below command:

ls -1a -d */ 

It returns something like this:

folder01/
folder02/
folder03/
...

Usually I store result of this script to a text file and then create a second shell script file which process folders which returned by ls command and store it in .sh file to run them as a batch. So shell file will be something like this:

./process_folder.sh sample/folder01/
./process_folder.sh sample/folder02/    
./process_folder.sh sample/folder03/
./process_folder.sh sample/folder04/

As you can see I run ./process_folder.sh over results of ls command and alos there is a small change an it is I've added sample/ before name of each folder.

So the questions is how can I do all this using a command in my shell? (As i remeber I could use | or > but I couldn't remember the details).

3

Don't programmatically parse the output of ls.

The output of ls is designed for human consumption, not programmatic. There are multiple ways in which parsing it directly can break, more or less subtly. Just as an example, if I run the command you gave, I get different output:

$ mkdir -p newdir/folder0{1,2,3}
$ cd newdir
$ ls -1ad */
folder01//
folder02//
folder03//
$

See those double slashes? That's because I have aliased ls to ls --color=auto -F.

It's better to use a tool that is designed for or can at least be well pressed into service for the job. I suggest turning to find.

$ mkdir -p newdir/folder0{1,2,3}
$ cd newdir
$ find . -mindepth 1 -maxdepth 1 -type d -printf './process_folder.sh sample/"%P"/\n'
./process_folder.sh sample/"folder03"/
./process_folder.sh sample/"folder01"/
./process_folder.sh sample/"folder02"/
$

-mindepth 1 -maxdepth 1 limits the search to only the given starting directories (only . in this case) and excludes the starting directory itself. -type d limits matches to only directories. -printf is an action that find can take, which prints metadata about the directory entry found with a given format; %P in the format string is substituted by the name of the entry found minus the starting directory. See man 1 find for more details.

If you want to create a script to run later, redirect the output of find to a file:

$ find . -mindepth 1 -maxdepth 1 -type d -printf './process_folder.sh sample/"%P"/\n' > process_folders.sh

If you want a single command that executes the commands immediately, instead pipe the output of find into a shell:

$ find . -mindepth 1 -maxdepth 1 -type d -printf './process_folder.sh sample/"%P"/\n' | bash

This is far less likely to break, and gives you what you want without turning to fancy rewriting of a command's output. As-is, I suspect that the only thing that can break this is if the directory names have double quotes in them.

  • I got three right answers, but this one is the most comprehensive one! Anyway I should thank Marius and Eugen – VSB Nov 5 '16 at 13:57
  • Besides, -mindepth 1 was a required trick. – VSB Nov 5 '16 at 13:59
  • @VSB Yes, without -mindepth 1 (or with the default -mindepth 0 explicitly specified), find also prints the starting directory, which is obviously not what you want. – a CVn Nov 5 '16 at 14:01
  • Oh, It seems this one will run, it will only print result which can be used as a shell script inside an .sh file. – VSB Nov 5 '16 at 14:03
  • 1
    @VSB Sure, you could replace -printf './process_folder.sh sample/"%P"/\n' with -printf 'printf "%%s\\n" "%P"; ./process_folder.sh sample/"%P"/\n' or something like that. Doing so will print the name of each directory as it is processed. (Yes, the double % and \ are intentional, and required.) – a CVn Nov 5 '16 at 14:28
2

You want a loop:

for d in $(ls -1a -d */); do
  ./process_folder.sh "sample/$d"
done
2

You may try the following command:

find . -type d -mindepth 1 -maxdepth 1 -exec bash -c ' /path/to/process_folder.sh "sample/${0##*/}" ' {} \;

This both finds the directories in questions, and runs process_folder on each one of them at the same time: a single command instead of two. Also, it is immune to parsing problems.

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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