On 03/21/2013 08:52 PM, Juho-Pekka Kuitunen wrote: > On Fri, Mar 22, 2013 at 3:05 AM, Bob Proulx <b...@proulx.com> wrote: >> Juho-Pekka Kuitunen wrote: >>> Reproduce example; >>> $ echo "testdir/testfile" | xargs -I '{}' echo '{}', dir: $(echo dirname >>> '{}') = $(dirname '{}')
>> The problem is the $(...) which is running the dirname during the >> earlier shell command line parsing pass and passing the result off to >> the xargs command. > > So if I understand correctly, subshell replacements gets executed > before xargs fills in the replacements? I tried to rule out this > wonkyness with the "$(echo '{}')" bit and it seemed to work in the > correct order. The echo should produce an empty string if the subshell > was evaluated too soon? If you want to see when the shell is evaluating $(), use 'set -vx': $ set -vx $ echo testdir/testfile | xargs -I '{}' echo '{}', dir: $(echo dirname '{}') = $(dirname '{}') echo testdir/testfile | xargs -I '{}' echo '{}', dir: $(echo dirname '{}') = $(dirname '{}') + echo testdir/testfile echo dirname '{}') dirname '{}') echo dirname '{}') echo dirname '{}' ++ echo dirname '{}' dirname '{}') dirname '{}' ++ dirname '{}' + xargs -I '{}' echo '{},' dir: dirname '{}' = . testdir/testfile, dir: dirname testdir/testfile = . $ set - set - + set - What you seem to want to do is invoke a shell instance on each file name; that would be done as follows: $ echo testdir/testfile | xargs -I {} sh -c \ 'echo "$1", dir: $(echo dirname "$1") = $(dirname "$1")' sh {} testdir/testfile, dir: dirname testdir/testfile = testdir Or again with shell tracing (note there are two levels of shells - the shell that spawns xargs, and the shell that xargs spawns, so I'm posting two different traces): $ set -vx $ echo testdir/testfile | xargs -I {} sh -c 'echo "$1", dir: $(echo dirname "$1") = $(dirname "$1")' sh {} echo testdir/testfile | xargs -I {} sh -c 'echo "$1", dir: $(echo dirname "$1") = $(dirname "$1")' sh {} + xargs -I '{}' sh -c 'echo "$1", dir: $(echo dirname "$1") = $(dirname "$1")' sh '{}' + echo testdir/testfile testdir/testfile, dir: dirname testdir/testfile = testdir $ set - set - + set - $ echo testdir/testfile | xargs -I {} sh -cvx 'echo "$1", dir: $(echo dirname "$1") = $(dirname "$1")' sh {} echo "$1", dir: $(echo dirname "$1") = $(dirname "$1") echo dirname "$1") echo dirname "$1" ++ echo dirname testdir/testfile dirname "$1") dirname "$1" ++ dirname testdir/testfile + echo testdir/testfile, dir: dirname testdir/testfile = testdir testdir/testfile, dir: dirname testdir/testfile = testdir By the way, your question is mostly related to shell, and a bit with xargs, and practically nothing to do with dirname. Your confusion on WHEN $() is expanded would apply no matter what executable you plug in instead of dirname. But since neither sh nor xargs belongs to coreutils, you might get better answers by asking on a general forum on shell programming subtleties. > > Very much possibly not a bug but I'm not 100% convinced yet. I've been > chuckling at this all evening, love a good brain teaser even if it > turns out to be something I overlooked instead of a bug. :-) Hopefully shell tracing has managed to convince you. -- Eric Blake eblake redhat com +1-919-301-3266 Libvirt virtualization library http://libvirt.org
signature.asc
Description: OpenPGP digital signature