[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#14023: dirname/basename unexpected results when run by xargs -I
From: |
Eric Blake |
Subject: |
bug#14023: dirname/basename unexpected results when run by xargs -I |
Date: |
Thu, 21 Mar 2013 21:11:09 -0600 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/20130311 Thunderbird/17.0.4 |
On 03/21/2013 08:52 PM, Juho-Pekka Kuitunen wrote:
> On Fri, Mar 22, 2013 at 3:05 AM, Bob Proulx <address@hidden> 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