-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?
Kusalananda
  • 333,661
FriendFX
  • 357
  • 2
  • @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 '23 at 06:30
  • In this scenario, find ... -print0 | xargs -0 is just a long-winded way of doing find ... -exec. – muru Oct 17 '23 at 06: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 '23 at 06: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 '23 at 06:36
  • "How can realpath --relative-to=../A be evaluated before the call to xargs?" Why can't it be? Run realpath --relative-to=../A % in your shell to see what it is evaluated to. – muru Oct 17 '23 at 06:48
  • @muru OK, then I don't understand how % can get substituted for the xargs input from the output of find. – FriendFX Oct 17 '23 at 06:51
  • It is not being substituted, since xargs is not there to substitute it. % is only special to xargs, the shell will just use % as it is. – muru Oct 17 '23 at 06:51

1 Answers1

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 %
Kusalananda
  • 333,661
FriendFX
  • 357