Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why using dirname in find command gives dots for each match?

I'm using find for a task and I noticed that when I do something like this:

find `pwd` -name "file.ext" -exec echo $(dirname {}) \; 

it will give you dots only for each match. When you substitute dirname with basename in that command you get the full pathnames. Am I screwing something up here or is this expected behavior? I'm used to basename giving you the name of the file (in this case file.ext) and dirname giving you the rest of the path.

like image 687
temp2290 Avatar asked Mar 11 '10 21:03

temp2290


People also ask

What does Dirname do in Linux?

dirname is a command in Linux which is used to remove the trailing forward slahes “/” from the NAME and prints the remaining portion. If the argument NAME does not contains the forward slash “/” then it simply prints dot “.”.

What is Dirname command?

dirname is a standard computer program on Unix and Unix-like operating systems. When dirname is given a pathname, it will delete any suffix beginning with the last slash ( '/' ) character and return the result. dirname is described in the Single UNIX Specification and is primarily used in shell scripts.

How do you exclude from find?

We can exclude directories by using the help of “path“, “prune“, “o” and “print” switches with find command. The directory “bit” will be excluded from the find search!


2 Answers

Consider the following script:

#!/bin/sh set -x find `pwd` -name "file.ext" -exec echo $(dirname {}) \; 

set -x shows how the expansion works and what the final command is. When run, it gives the following output:

++ pwd ++ dirname '{}' + find /home/kibab -name file.ext -exec echo . ';' 

So, the first thing that is expanded is the pwd. Second is $(dirname {}). The result of those two commands is then dropped into the find command. Thus, you're telling find to -exec echo ., so you're seeing the expected output.

When you substitute basename for dirname, the expansion still takes places, but the results of the expansion are different:

  1. pwd is expanded to the current path. In my example above, the result is /home/kibab

  2. basename {} is executed. The result of this command is {}.

  3. The find command is executed with the above substitutions in place. The final command executed looks like this:

    find /home/kibab -name '*.png' -exec echo '{}' ';'

Upon inspecting the above command, you'll notice that the command now simply echo's whatever file was found.

Perhaps you want something like this?

find `pwd` -name "file.ext" -printf "%f\n" 
like image 125
Kaleb Pederson Avatar answered Oct 02 '22 13:10

Kaleb Pederson


So the problem is that $(...) or `...` starts a new shell before make the replacement.

Consider using bash -c:

$ find . -name '*.PNG' -exec bash -c 'git mv {} $(dirname {})/$(basename {} .PNG)48.png' \; 

That renames any icon on a git repo to a more standard form.

Here {} is replaced before executing anything, so the problem is gone.

For that example, TMTOWTDI, but I try to keep it simple so you can start whatever you really need to do.

like image 36
albfan Avatar answered Oct 02 '22 12:10

albfan