I want to create a script which executes a command(similar to make command) in every directory which contains a file called
Since your tag indicates
bash, you can use the
shopt -s globstar for d in **/; do if [[ -f "$d/my_suites.cfg" ]]; then cd "$d"; make; cd -; fi; done
This will iterate over all directories and sub-directories of the current directory, check if a file
my_suites.cfg exists, and if so, changes to that directory, calls
make, and changes back to the original directory.
So to generalize the question: You want to run a bash command on each 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 (
$ find ~ -name "my_suites.cfg" -type f \ | xargs dirname \ | xargs -d '\n' <command-to-run-on-the-file>
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$"
mlocatelooks 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.
--basenameoption specifies that we are looking for the direct name of the file, not including the path/directories of it.
--regexoption 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
findgoes 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.
-nameoption 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.
-typeoption 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
-doption: specifies, which character delimits the arguments from each other (here: a space).
-Ioption: 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:
echoprints "hello world" to the standard output (
- The pipe (
|) gives this value ("hello world") to the following command, which happens to be
xargssearches for occurences of the delimiter in the argument and splits the argument where it finds the delimiter.
xargsloops through the newly created arguments and runs the command with the argument value instead of