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.

2
  • Because the shell replaces $(basename {}) with {} before xargs starts. There's probably a duplicate question somewhere. I know one on Super User. Commented Aug 2, 2022 at 13:21
  • 2
    Never do for i in $(ls). It is bad practice, likely to break, and is harder than the simpler and safer for i in *. Commented Aug 2, 2022 at 13:50

1 Answer 1

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.)

2
  • "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. Commented Aug 3, 2022 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 Commented Aug 3, 2022 at 20:17

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.