How to find a file and cd to its dirname using command substitution

Many times I know the name of a file on my Linux machine, say unknown.txt, but I don't know the directory the file is in.

If I want to change directory to the directory folding the file, I used to do a 2-step process:
$ find / -name unknownfile.txt 2>/dev/null
/home/peter/status/2007/november/unknownfile.txt


Note: if you know more about where that file may be, you can always make the starting point of the find more specific (say "/home/peter" instead of just "/").

Then, I manually enter the cd command with the path discovered from the last step.
$ cd /home/peter/status/2007/november
$


I got tired of re-entering the directory name in this 2 step process. So, I set out to see if I can automate it further.

Here we go.

There may be more than 1 file of that file name, and if so, let's take the first one.

$ find / -name unknownfile.txt  2>/dev/null | head -n 1
/home/peter/status/2007/november/unknownfile.txt



We need to extract just the directory path, and leave out the filename (so that we can cd to the directory).

The dirname command should be able to do that, but alas, dirname cannot take its input from STDIN. dirname expects the file name as a command line parameter. The following will fail.
$ find / -name unknownfile.txt  2>/dev/null | head -n 1  | dirname
dirname: missing operand
Try `dirname --help' for more information.


This is where command substitution comes in.

The final command is:
$ cd $(dirname $(find / -name unknownfile.txt  2>/dev/null | head -n 1))
$ pwd
/home/peter/status/2007/november
$


Let's break it down. Using command substitution, the output of one command becomes the input parameter to another command.

The first command substitution we use is:
dirname $(find / -name unknownfile.txt  2>/dev/null | head -n 1)


In this case, the output of "find / -name unknownfile.txt 2>/dev/null | head -n 1" becomes the input to dirname.

Then, we again use command substitution to make available the output of dirname as the input to cd.

cd $(dirname $(find / -name unknownfile.txt  2>/dev/null | head -n 1))