help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] Commands run via xargs and bash returns different result


From: Richard Taubo
Subject: Re: [Help-bash] Commands run via xargs and bash returns different results
Date: Mon, 3 Feb 2014 22:52:32 +0100

On Feb 3, 2014, at 8:32 AM, Bob Proulx <address@hidden> wrote:

> Richard Taubo wrote:
>> I am running the following command via xargs and bash with no problems;
>>      /usr/bin/mdfind text -0 -onlyin /This/Path | /usr/bin/xargs -0 -I {} 
>> bash -c 'echo -e "{}";
> 
> Unterminated a single quote at the end.

Thanks (copy/paste error).


> It is better if you can create a small test case using standard
> utilities like 'find' or echo/printf/seq or bash so that the rest of
> us can follow along.  Being a free(dom) software list most of us don't
> have Apple Mac computers but are using GNU system software.  So we
> don't have mdfind on most of our systems.  I'm just say'in…

Yes, the test case was not the best, sorry about that.
mdfind should be available via Darwin and Darwin derivatives,
so I guess the freedom part could be questioned, but I get
your point :-)

> 
>> When I switch to following command though, to better manipulate the results, 
>> most of the results from the earlier command above get returned, but some 
>> lines simply
>> returns  {} instead of the correct result:
>>      /usr/bin/mdfind text -0 -onlyin /This/Path | /usr/bin/xargs -0 -I {} 
>> bash -c 'my_path="{}";echo -e "$my_path";'
> 
> Hmm...  Why are you using a full hard coded path to /usr/bin?  Why not
> just "mdfind" and "xargs"?  Is /usr/bin not in your PATH?  If not then
> it should be.  Hard coded paths are Evil.

Do you mean Evil as in “Eval is evil” or due transportability issues?
mdfind was in the path, but I guess the full path came from a mdfind example
I have seen. So far the script only lives on my own machine, but thanks for the 
hint. 

> 
> Do you have a test case?  This worked okay for me.
> 
>  $ printf "%s\0" {0..9} | xargs -0 -I {} bash -c 'my_path="{}";echo -e 
> "$my_path";'
>  0
>  1
>  2
>  3
>  4
>  5
>  6
>  7
>  8
>  9
> 
> I assume you expect that the {} in the assignment will be replaced by
> xargs with the string read from stdin.  It will go in the first part.
> Which means that it will be data dependent whether it will be happy or
> not.  Not a good idea.  If I craft a file name that includes single
> and double quotes then I can probably break your shell quoting.  It
> isn't like variable expansion where the shell has already parsed the
> quotes.  This is happening with xargs which processes the input before
> invoking the command.  This seems a fragile technique.
> 
> I think you would be better off piping to an actual shell script.
> 
>  printf "%s\0" {0..9} | while read -r -d '' v; do echo "$v";done
> 
> Of course you can do what you want in the body of the while loop.  But
> this is safer than the xargs {} substitution in the shell variable
> assignment.

Okay, I have looked into that, and that seems to give better results. Thanks!


> 
>> It seems like the added step of including a variable hinders the mdfind 
>> command 
>> to return the real result, so it skips a few paths here and there.
> 
> First, the mdfind command in the first part of the pipeline operates
> completely independent of the second part of the pipeline.
> 
> This pipeline:
> 
>  cmd1 | cmd2
> 
> Will be competely identical to this:
> 
>  cmd1 > file1
>  cmd2 < file1
> 
> For debugging try it that way.  Don't use a pipeline.  Use a file just
> for debugging.
> 
>  mdfind text -0 -onlyin /This/Path > tmpfile
>  xargs -0 -I {} bash -c 'my_path="{}";echo -e "$my_path";' < tmpfile  
> 
> It will behave the same but will split the parts up so that you won't
> think one part of the pipeline is affecting the other part.
> 
> But!  What are you trying to do with {} in the second part of the
> pipeline?  Sorry for my saying so but that is just bizarre.  The {} is
> special to xargs.  If you hide it in a one-liner inside the bash then
> xargs won't see it.  Or worse will see it in the wrong place.

By setting: my_path="{}” I was trying receive each of the paths
handed over from mdfind via xargs, and then use this variable to
create html list based output, e.g something like:  
        "<li>$my_path</li>”
(it was a little more complicated than that, e.g. splitting based on
forward-slashes, conditional expressions etc, but the output was 
meant for html list output).

Based on your description above, I understand there is a correct/safer/better 
way to accomplish this, but you would humour me if you would point out
the “bizzarity" part of the command. Clunky and error-prone, yes, but what
makes it bizarre? I had to somehow grab the output from mdfind, and it
seemed to me at the time, using this clunky method, that I could only
grab the output using "{}” . . .  I am sure I am wrong :-)


> 
>> Is there a better way to go about this, so I can be sure that the
>> equivalent of the last command returns the same as the first
>> command?
> 
> I think you might be getting confused by the "echo -e" part.  That is
> a terribly nonportable command.  The -e causes escape sequences to be
> interpreted.  It is in-band control.  It is data dependent.  I suggest
> you avoid using it.  Use printf instead.  But why do you have the -e
> there in the first place?  It can only be trouble.  Lose the -e.
> 
> Try this:
> 
>  $ printf "%s\0" {0..9} | xargs -0 -I {} bash -c 'my_path="{}";printf "%s\n" 
> "$my_path";'
> 
> But I still can't imagine what the script approach will be doing for you.
> 
> Use the "while read -r -d '' var" technique instead.  It is safer. :-)

Again, thanks for your feedback!

Richard Taubo


reply via email to

[Prev in Thread] Current Thread [Next in Thread]