Noch ein Techie im Web

Running a bash command recursively

Bash: Execute a command in each directory with file my_suites.cfg?

"I want to create a script which executes a command (similar to make command) in every directory which contains a..."

So to summarize the question: You want to run a bash command on each folder that contains a file that has a specific name, one at a time.

Assuming, that you are willing to use existing tools and not write everything from scratch by yourself, here are some ideas:

TL;DR (Too long, didn’t read)

If it doesn’t matter whether the newest files are not recognized yet:

$ mlocate --basename --regex "^my_suites.cfg$" \
| xargs dirname \
| xargs -d '\n' <command-to-run-on-the-file>


Else if efficiency is not so important (assuming, that we are searching recursively in the home directory ( ~ ) only:

$ find ~ -name "my_suites.cfg" -type f \
| xargs dirname \
| xargs -d '\n' <command-to-run-on-the-file>


Full Version

Finding the files

If the files you are looking for are scattered all over the system, you should care about effectiveness.

The fast(er) way

With some downsides

$ mlocate --basename --regex "^my_suites.cfg$"

  • mlocate looks up file paths in a database that is updated once a day for most distributions. So it may not recognize recently created or recently moved files. But because it looks into the database instead of going through the file system itself, it’s search is very efficient.
  • The --basename option specifies that we are looking for the direct name of the file, not including the path/directories of it.
  • The --regex option enables regular expressions being allowed in the search pattern. (The ^ expects the string to start there and the $ expects the string to end there.)

The “always up-to-date” way

$ find / -name "my_suites.cfg" -type f

  • find goes through basically every folder it can find and lists every file which is named my_suites.cfg. Because of that many reading-operations that it has to do, the more folders it searches the slower it gets.
  • The -name option specifies, that my_suites.cfg is the name of the file, instead of i.e. a folder that contains the file that we are looking for.
  • The -type option specifies, that we are looking for a file , not for a directory, symlink, socket or something.

Running a custom command on each of the files

… that’s what xargs is for

A simple example

$ echo "some simple example" | xargs mkdir
$ # now there are three directories, named by the echoed words
$ ls
example  simple  some


Something more complex:

$ echo "hello world" | xargs -d ' ' -I % echo 'Print a word: %'
Print a word: hello
Print a word: world

  • -d option: specifies, which character delimits the arguments from each other (here: a space).
  • -I option: All occurences of the given character ( % in this example) will be replaced by the argument that came from the pipe (before | )

This is what happens in the above example:

  1. echo prints “hello world” to the standard output ( stdout ).
  2. The pipe ( | ) gives this value (“hello world”) to the following command, which happens to be xargs .
  3. xargs searches for occurences of the delimiter in the argument and splits the argument where it finds the delimiter.
  4. xargs loops through the newly created arguments and runs the command with the argument value instead of %

Further readings

#stackexchange #bash #gnu/linux