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

前端 未结 7 1460
清酒与你
清酒与你 2021-02-01 15:16

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

相关标签:
7条回答
  • 2021-02-01 15:16

    I don't know why you're getting that, but try this:

    find `pwd` -name file.ext |xargs -l1 dirname
    
    0 讨论(0)
  • 2021-02-01 15:19

    This is because find prints paths relative to the path it searches from. If you tried this search from / you would get ``pwd\ for each path.

    0 讨论(0)
  • 2021-02-01 15:26

    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"
    
    0 讨论(0)
  • 2021-02-01 15:26

    $(dirname {}) is evaluated by the shell before being passed to find. The result of this evaluation is ., so you're just telling find to execute echo . for each file it finds.

    basename {} evaluates to {}, so with $(basename {}) substituted for $(dirname {}), find will execute echo {} for each file. This results in the full name of each file being echoed.

    If you want to output the result of dirname for each file found, you can omit the echo:

    find `pwd` -name "file.ext" -exec dirname {} \;
    
    0 讨论(0)
  • 2021-02-01 15:29

    you do not have to call dirname() for each file found. with GNU find, you can use -printf and its faster this way

    find /path -type f -iname "*.ext" -printf "%h\n"
    
    0 讨论(0)
  • 2021-02-01 15:40

    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.

    0 讨论(0)
提交回复
热议问题