-1
user@debian:~/test/B$ find ..
..
../A
../A/x
../A/y
../A/z
../B
user@debian:~/test/B$ find ../A -type f -print0 |xargs -0 -i% realpath --relative-to=../A %
x
y
z
user@debian:~/test/B$ # But
user@debian:~/test/B$ find ../A -type f -print0 |xargs -0 -i% echo $(realpath --relative-to=../A %)
../B/../A/x
../B/../A/y
../B/../A/z

Muru suggested that the answers to the question "find -exec command options with basename" might answer this question, but I'm not using find with -exec.

I don't understand muru's explanation "the command substitution around realpath is executed by the shell before it even starts running xargs (as a step in evaluating what the arguments to xargs should be)":

  • How can realpath --relative-to=../A be evaluated before the call to xargs?
  • Even if it is evaluated, what does it evaluate to, and why does that lead to a different output?
9
  • 2
    Does this answer your question? find -exec command options with basename
    – muru
    Oct 17, 2023 at 6:18
  • @muru This is somewhat helpful but the answer mentions "the command substitution around basename is executed by the shell before it even starts running find (as a step in evaluating what the arguments to find should be). I'm not exactly sure whether that applies to my case as I'm not using find with -exec.
    – FriendFX
    Oct 17, 2023 at 6:30
  • In this scenario, find ... -print0 | xargs -0 is just a long-winded way of doing find ... -exec.
    – muru
    Oct 17, 2023 at 6:32
  • @muru Functionally equivalent maybe, but what I'm after is an explanation of why the substitution doesn't work that way. What is different between my two examples?
    – FriendFX
    Oct 17, 2023 at 6:35
  • Exactly the bit you quoted, mutatis mutandis: "the command substitution around realpath is executed by the shell before it even starts running xargs (as a step in evaluating what the arguments to xargs should be)".
    – muru
    Oct 17, 2023 at 6:36

1 Answer 1

0

Explanation

Thanks to @muru for walking me through finding my own answer. Here is what is happening:

When the shell sees the command line

find ../A -type f -print0 |xargs -0 -i% echo $(realpath --relative-to=../A %)

it first evaluates the command subsitution

realpath --relative-to=../A %

which evaluates to ../B/%.

Therefore the effective command that is being executed when find starts is this:

find ../A -type f -print0 |xargs -0 -i% echo ../B/%

...which doesn't call realpath at all, but simply appends the find output to ../B/.

Workaround

Don't use a command substitution there, use plain realpath to do its work before doing whatever you wanted to do in the first place (not very much in this example, but this could obviously be extended):

find ../A -type f -print0 |xargs -0 -i% realpath -z --relative-to=../A % |xargs -0 -i% echo %

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .