I have a script, say data.sh, which takes many data files in the same directory and process them. I have many directories with different files but I have the same script in all. I can routinely go to each dir and execute data.sh by ./data.sh but it is tedious.

  • How can I run data.sh from the parent dir? My first guess of ./parent/dir1/data.sh does not work.

  • I'd like to excecute all data.sh scripts simultaneously. How? I can find all data.sh by find command in the parent dir: find . -name data.sh. How to -exec with them? The following has the same problem as in my first point:

    find . -name data.sh -exec ./{} \;

The obvious solution would be to change data.sh and make it accept one or more arguments, those being the files (and perhaps directories) being worked on.

Say the script currently contains:

some-command ./*    # ← this is where it works on all files

Then you'd change it to:

some-command "$@"

Here, $@ is all arguments passed to data.sh, and you'd only need to call it like this:

/path/to/data.sh /path/to/another/directory/*

Then the script would run on all files in the other directory. Of course, without knowing the exact inner workings of data.sh it's impossible to suggest how to change it, specifically.

If you want to keep data.sh as-is, you need to change the current directory every time you call it. This will make your script "think" it's inside another directory.

You could achieve this by using cd (or pushd/popd) from a shell launched by find:

find . -name "data.sh" -exec sh -c 'cd "$(dirname "$0")" && ./data.sh' {} \;

Or you could temporarily cd the directory in a subshell (this is the parentheses around cd), maybe with globs so you can skip using find (the ** will recursively match all directories):

shopt -s globstar
for script in **/data.sh; do
    ( cd "$(dirname "$script")" && ./data.sh )

If you hadn't used a subshell in the above command, the second cd call would fail since it'd try to cd from the first found directory that contains data.sh. You can avoid this with pushd/popd:

for script in **/data.sh; do
    pushd "$(dirname "$script")" && ./data.sh
|improve this answer|||||
  • WOW! I REALLY appreciate your super detailed and helpful comment. This was exactly the one I was hoping to get. I tested your 2nd option (with find command ) and worked like charm. But I learned also a great deal by the other ways. – physiker Aug 9 '14 at 19:59

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.