Search code examples
bashshellfind

How do I find (using bash) the top-level file with a particular name within a directory path?


I have a bash script that runs mysql scripts and that takes the mysql database name from a file rather than having me type in it as an option (so that I won't mistakenly type in the wrong one). I set this by putting the mysql database name within a file called mysql_db_name that is either in the same directory as the script I'm running or somewhere above that directory in its directory path: it could be in the parent directory, the parent's parent etc. This bash script runs a mysql script when I type:

bash_script mysql_script_name

I would like to have my bash script find the top-level file caled mysql_db_name within the path of the mysql_script_name script.

My current code snippet to do this is:

MFILE=`find / -exec bash -c '[[ $PWD != "$1"* ]]' bash {} \; -prune -name mysql_db_name -print`

This usually works, but not if there is another directory in the parent directory with a file called mysql_db_name whose directory name is a subset of the current directory name. For example, if this exists:

parent/directory1/mysql_db_name
parent/directory11/mysql_db_name
parent/directory11/mysql_script_name.sql

Then if I try to run mysql_script_name in directory11 the bash_script will fail. It would not fail if directory1 above was instead named directory2.

This problem is similar to Find file by name up the directory tree, using bash but I can't get those solutions to work.


Solution

  • If you know the file name and the directory path it's in, there is no sane reason to use find here anyway.

    path='/'
    for dir in path to deepest possible dir containing the file; do
        path=$path/$dir
        test -e "$path/mysql_db_name" && break
    done
    test -e "$path/mysql_db_name" || { echo "$0: mysql_db_name not found" >&2; exit 2;}
    : proceed to use "$path/mysql_db_name"
    

    This proceeds forward to find the highest directory with a file with that name. It should not be hard to see how to turn it around to start from the deepest directory; here is one approach.

    path=/path/to/deepest/possible/dir/containing/the/file
    while [ "$path" ]; do
        test -e "$path/mysql_db_name" && break
        path=${path%/*}
    done
    test -e "$path/mysql_db_name" || { echo "$0: mysql_db_name not found" >&2; exit 2;}
    : proceed to use "$path/mysql_db_name"