0

Why when I do this (I know, it's stupid) it returns the full path, not only the filename as expected? ls -l | awk '{print $9}' | xargs -I% find ./my_dir -type f -name "%" -exec echo $(basename {}) \;

And, yes, I know, it's stupid but the goal was to cp basename{} to {} (and, in the and, I use a loop for i in $(ls); do find ./my_dir -type f -name $i -exec cp $i {} \;; done)

Thanks.

Alysko
  • 103

1 Answers1

4

Your code will fail for any filename that contains a space (e.g this one.txt) or on any system where the user name or group name contains spaces (a system joined to Active Directory, for example).

The construct for i in $(ls) should not be used. Instead, use a wildcard glob, for i in *.

Finally, in direct answer to your question about $(basename {}). The $( ... ) value is not protected from the shell with single-quotes, and so it is evaluated before the command is executed. The result of $(basename {}) is simply {} and therefore,

xargs -I% find ./my_dir -type f -name "%" -exec echo $(basename {}) \;

is parsed and executed as if you had typed this,

xargs -I% find ./my_dir -type f -name % -exec echo {} \;

You were probably looking for something like this

for i in *
do
    find ./my_dir -type f -name "$i" -exec cp "$i" {} \; -quit
done

Don't forget that you should always double-quote your $ variables and expressions when you use them. (To be fair, it wouldn't have helped in this case, but it's something you need to get used to doing.)

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • "The $( ... ) value is not quoted, and so it is evaluated before the command is executed." -- it'd be evaluated (and basename would run) before find starts even with quoting. – ilkkachu Aug 03 '22 at 19:51
  • well, yes, with single quotes the shell wouldn't run it but before starting find, but even then find wouldn't expand it either. Because, well, it's just not something it does by itself, hence the find -exec sh -c '...' sh {} \; idiom – ilkkachu Aug 03 '22 at 20:17