Reputation: 8416
Using bash
, how can I find a file with a specific name somewhere up the directory tree from the pwd
?
To be more clear. I want to find a file that sits in my working directory's root, but I don't know where the root is, and my pwd
might be anywhere below the root.
Upvotes: 18
Views: 5640
Reputation: 2166
similar to the answer of @kev but as a function attempting to locate a (sub-)file upwards toward the root folder (prefering string-manipulation over function calls like dirname tr etc)
# @usage: `dir_containing [--stop=<dir>] <sub-path-to-find>`
# @params: 1) (sub-)filename to find, 2) starting-dir (defaults to PWD)
# @options: --stop=<dir> directory where to stop searching (default: <root>)
# @return: directory-path (where the (sub-)filename was found),
# otherwise empty string (along with a non-zero errorcode)
# @throws: #400 if called without parameters, #404 if not found
# @alias: upfind, find_upward
dir_containing() {
local stop=""; [[ "$1" = --stop=* ]] && { stop="$( realpath "${1/--stop=/}" )"; shift; }
[ "$1" ] || return 400
local d="$( realpath "${2:-"$PWD"}" )"
while [ "$d" ] && [ "$d" != "$stop" ] && [ ! -e "$d/$1" ]; do d="${d%/*}"; done
[ -e "$d/$1" ] && echo "${d:-/}" || return 404
}
Upvotes: 0
Reputation: 161954
Find file.txt
up to root
x=`pwd`
while [ "$x" != "/" ] ; do
x=`dirname "$x"`
find "$x" -maxdepth 1 -name file.txt
done
Upvotes: 19
Reputation: 2415
local DIR=$(pwd)
while [ ! -z "$DIR" ] && [ ! -f "$DIR/myFile.txt" ]; do
DIR="${DIR%\/*}"
done
echo $DIR/myFile.txt
Upvotes: 10
Reputation: 323
I have the following function defined in my ~/.bashrc:
dnif () {
# Recursively list a file from PWD up the directory tree to root
[[ -n $1 ]] || { echo "dnif [ls-opts] name"; return 1; }
local THERE=$PWD RC=2
while [[ $THERE != / ]]
do [[ -e $THERE/${2:-$1} ]] && { ls ${2:+$1} $THERE/${2:-$1}; RC=0; }
THERE=$(dirname $THERE)
done
[[ -e $THERE/${2:-$1} ]] && { ls ${2:+$1} /${2:-$1}; RC=0; }
return $RC
}
which will search for a name you provide as a parameter in each directory upwards from the current to the root, and if found, list it with 'ls' and the optional ls -options that you provide. Example output:
me@host:~/dev/example
$ dnif; echo $?
dnif [ls-opts] name
1
me@host:~/dev/example
$ dnif -alp nonesuch; echo $?
2
me@host:~/dev/example
$ dnif -alp .bashrc; echo $?
-rw-r--r-- 1 me mine 3486 Apr 3 2012 /home/me/.bashrc
0
me@host:~/dev/example
$ dnif -d .
/home/me/dev/example/.
/home/me/dev/.
/home/me/.
/home/.
/.
Please note:
Upvotes: 4