Export d, then it will be available in your bash inline script. You also don't need bash at all here. Your (hopefully slimmer/faster) sh would do as well. Also, you don't need to run one shell per file. You can pass more files to your inline script with the -exec cmd {} + variant:
d=/tmp/foo
export d
find "$d" -type f -exec sh -c '
for file do
relative=${file#"$d/"}
dir=${file%/*}
relative_dir=${relative%/*}
relative_dir=${relative_dir:-.}
printf "%10s: %s\n" full "$file" \
relative "$relative" \
dir "$dir" \
reldir "$relative_dir"
done' sh {} +
Which gives:
full: /tmp/foo/bar/can/haz/bzr.txt
relative: bar/can/haz/bzr.txt
dir: /tmp/foo/bar/can/haz
reldir: bar/can/haz
But if you only need the relative path, it may be simpler just to do:
(cd -P -- "$d" && find . -exec sh -c 'for file do...' sh {} +)
That would also make the command arguments passed to sh shorter so would allow find to pass more arguments to sh.
Note that there's nothing GNU-specific in your find command nor mine. That should work in any POSIX-compliant find implementation, not only the GNU one. The only non-POSIX part in your question was obviously bash and the ${1:offset} operator which is a Korn shell operator, not in POSIX sh.
For a recursive file lookup that allows you to specify the file type, see also zsh:
(cd -P -- "$d" &&
for file (**/*(ND.)) {
dir=$file:h
printf '%10s: %s\n' relative $file reldir $dir
})
Above, the . is the equivalent of find's -type f (only regular files), while D is to also include hidden ones like find does.
As a side note, in the general case:
c=$a$b; d=${c:${#a}}
[ "$b" = "$d" ] && echo yes
Is not guaranteed to output "yes", because the ${#var} and ${var:offset} operators work with characters, not bytes.
For instance in a UTF-8 locale, it would not output yes with these values of a and b:
a=$'St\xc3' b=$'\xa9phane'
With those, $c would contain my first name (Stéphane) $a contains half of that é character and $b the other half, ${#a} would be 3 (2 characters and 1 byte not forming a valid character but still counted).
So $d would be phane, not $'\xa9phane'.
In the specific case of d=$a/$b though, it should be OK, as none of the character set generally available in system locales would have a character other than / that contains the encoding of /.
/tmp/foo/file.txt?