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: Bob Proulx
Subject: Re: [Help-bash] Commands run via xargs and bash returns different results
Date: Mon, 3 Feb 2014 00:32:50 -0700
User-agent: Mutt/1.5.21 (2010-09-15)

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.

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...

> 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 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.

> 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.

> 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. :-)

Bob



reply via email to

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