This question already has an answer here:

My requirement is that shell script should print the folder name of the file.

For example comp.class is present in D:/Practice/HelloWorldPractice/bin folder, I should get output after executing command is bin.

My command searches a file and prints the full path of that file . After that, it removes the filename from full path. At the end, it remove everything except folder name of file.


echo $(find "${filesDirName}" -name ${file}) | awk -F '${file}' '{ print $1 }'| awk -F '${filesDirName}' '{ print $2 }'

output empty output


When I am entering below command in terminal it is working fine.... But when I am doing it through variables, I am not able to get output.

echo "$(find "/D/Practice/HelloWorldSagar" -name comp.class)" | awk -F 'comp.class' '{ print $1 }'| awk -F '/D/Practice/HelloWorldSagar' '{ print $2 }'



marked as duplicate by Isaac, Jeff Schaller, Christopher, Mr Shunz, Thomas Jan 12 at 18:09

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • I get this is some kinf of homework or tutorial (or else you can use $(basename $(dirname $f)) to get folder name of $f ). 1) there is non need to echo $(find ...) 2) I wouldn't use a directory name as separator. 3) use -F/ and NF 's awk variable. $NF is last field and $(NF-1) the one before. – Archemar Jan 6 at 14:15
  • Could you please explain why my code is not working? Because I want to make work my above code as my file might be present inside subdirectory of another subdirectory. In that case, I need to print path in the way like /bin/hello. – Sagar Mamidala Jan 6 at 14:51
  • Thank you so much............. :) It worked :) :D – Sagar Mamidala Jan 6 at 14:58

Using comp.class as the field delimiter (or trying to, the variable expansion is single quoted in your code) for awk makes little sense to me, as does running multiple awk programs ofter each other in a pipeline.

As far as I understand you want the filename of the directory that contains the comp.class file.

This does that:


find "$topdir" -type f -name "$filename" \
    -exec sh -c 'basename "$(dirname "$1")"' sh {} ';'

This looks for all files called comp.class in or below /D/Practice/HelloWorldSagar. When one is found, a short shell script simply prints out the base name (the filename portion of a pathname) of the directory path of the found pathname.

Alternatively, look for directories, and then separately test for the existance of the file:

find "$topdir" -type d \
    -exec test -f {}/"$filename" ';' \
    -exec basename {} ';'

This tests for existence of comp.class in all found directories under $topdir (including $topdir itself). When the file is found, the base name of the found directory is printed.

The difference between the two approaches is that the second approach would also detect a symbolic link called comp.class that points to a regular file.


Just in case it's not the base name of the directory you want, but the relative path beneath $topdir:

find "$topdir" -type f -name "$filename" \
    -exec sh -c 'd="$(dirname "$2")"; printf "%s\n" "${d#$1/}"' sh "$topdir" {} ';'

This is a variation of the first solution that extracts the directory name into a variable d, and then prints the value of that directory pathname with $topdir deleted from the start of it.

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