1

I want to create a script which executes a command(similar to make command) in every directory which contains a file called my_suites.cfg.

4
  • Welcome to the site. Can you expand your question to show what you already tried? Where are the directories located - directly beneath the "current" directory, or can they be deeply nested inside a directory tree? – AdminBee Mar 9 at 14:37
  • There's no concrete pattern to how the directories are. But the file my_suites.cfg will be present in each directory. When I do this manually, I need to cd into a directory with such file to execute the make command which will generate a json file which I need to copy to a different location. – Phi-Long Vu Mar 9 at 14:54
  • Is there any kind of root/master directory under which all subdirectories including those who possibly contain the file my_suites.cfg belong to? – ex1led Mar 9 at 14:56
  • Yes, it's a code repository. – Phi-Long Vu Mar 9 at 14:57
1

Since your tag indicates bash, you can use the globstar option:

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.

2
  • I've expanded the bash script that you have provided so that it will copy the generated files to a /debug folder. The necessary sub-folders are created for each file in the loop depending on the $d variable. I would like to concatenate all of the files that are stored in the /debug folder in their nested folder-structure. Is this command correct for such purpose if I'm standing in the /debug folder? cat **/my_file.json >my_file.json – Phi-Long Vu Mar 9 at 15:46
  • @Phi-LongVu I think that requires further clarification that exceeds the scope of the comment section. I would recommend that you open another, follow-up question, and create a link to this question for reference. – AdminBee Mar 10 at 8:31
1

You could use find to execute a command (example: pwd) with a working directory where the named file ist found:

find /path/to/repository -type f -name my_suites.cfg -execdir pwd \;

/path/to/repository can also be a relative path (even ".")

0

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 (~) 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

2
  • you still need to go from the filename /foo/bar/my_suites.cfg to running the command in /foo/bar – ilkkachu Mar 9 at 21:57
  • @ilkkachu right, thanks! – Hoschi-IT Mar 9 at 22:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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