Re: builtin read stops at '\0'

2011-05-19 Thread Greg Wooledge
On Wed, May 18, 2011 at 02:10:39PM +0200, Rafaël Fourquet wrote:
> If a line containing the '\0' is read into a variable, the content
> of this variable does not contain the part after the '\0' character.
> 
> Repeat-By:
> echo -e 'a\0b' | (read f; echo $f)
> 
> The output is 'a', and '\0b' is stripped.

Bash stores strings the same way C does.  NUL marks the end of a
string.  So, even if f does contain a\0b, any attempt to retrieve
the value of f is going to stop at the NUL byte.

If you want to handle a stream of NUL-delimited strings in bash, the
best approach is to use read -d '', thus:

imadev:~$ printf '%s\0' one two three | while read -r -d '' s; do echo "<$s>"; 
done




read -d '' means "stop at NUL, instead of stopping at newline".



Re: builtin read stops at '\0'

2011-05-19 Thread Rafaël Fourquet
>
>
> If you want to handle a stream of NUL-delimited strings in bash, the
> best approach is to use read -d '', thus:
>
> imadev:~$ printf '%s\0' one two three | while read -r -d '' s; do echo
> "<$s>"; done
> 
> 
> 
>
> read -d '' means "stop at NUL, instead of stopping at newline".
>

Thanks for your reply. I was aware of your solution, but in my situation the
'\0' problem makes things more complicated:
I have a program which outputs groups of filenames. Each group is separated
by a newline, and within each group,
each name is separated by '\0'. I want to pipe each group to xargs -0. But
because of this '\0' implementation detail (I did not find it is
documented).
the following solution (working in zsh) don't work in bash (and I couldn't
find a  non-convoluted solution in bash) :

myprog | while read group; do echo $group | tr -d '\n' | xargs -0 ls -1;
done

If I use , I don't know how to break on each
line...
A solution with mapfile would be even better, but mapfile has the same
problem as read in this regard.


Re: builtin read stops at '\0'

2011-05-19 Thread Greg Wooledge
On Thu, May 19, 2011 at 03:23:55PM +0200, Rafaël Fourquet wrote:
> I have a program which outputs groups of filenames. Each group is separated
> by a newline, and within each group,
> each name is separated by '\0'.

That seems backwards somehow... the "stronger" delimiter (NUL) is used
in the inner group, and the "weaker" delimiter (newline) in the outer.
Oh well -- I assume you have no control over that.

Here's what I'd do: just use tr to swap the delimiters.

while read -d '' -r group; do
  mapfile -t files <<< "$group"
  ...
done < <(tr '\n\0' '\0\n' < "yourfile")

> I want to pipe each group to xargs -0.

Not what I'd do.



Re: builtin read stops at '\0'

2011-05-19 Thread Rafaël Fourquet
>
> Here's what I'd do: just use tr to swap the delimiters.
>
> while read -d '' -r group; do
>  mapfile -t files <<< "$group"
>  ...
> done < <(tr '\n\0' '\0\n' < "yourfile")
>
> > I want to pipe each group to xargs -0.
>
> Not what I'd do.
>

Thanks!
But is there something wrong with xargs? or is it my use of "echo ...|xargs"
(I did not know "here strings")
Do you mean, in your example, that e.g.
... do mapfile -t files <<< "$group" ; ls -1 "${files[@]}"; done ...
is better than:
... do  xargs -d '\n' ls -1  <<<"$group"; done ...


Re: builtin read stops at '\0'

2011-05-19 Thread Greg Wooledge
On Thu, May 19, 2011 at 04:30:40PM +0200, Rafaël Fourquet wrote:
> Do you mean, in your example, that e.g.
> ... do mapfile -t files <<< "$group" ; ls -1 "${files[@]}"; done ...
> is better than:
> ... do  xargs -d '\n' ls -1  <<<"$group"; done ...

imadev:~$ group=$'foo\nbar\n"hi mom"\n'
imadev:~$ xargs -d '\n' printf '<%s> ' <<< "$group"
xargs: unknown option: -d

Must be some GNUism you're attempting to use (granted, the -0 was also
a GNUism, but it's at least one I've heard of -- and is also present
on most BSD boxes).

If my guess is correct, your -d option is supposed to turn off the
blatant historical stupidity and uselessness that characterize xargs:

imadev:~$ xargs printf '<%s> ' <<< "$group"
   imadev:~$ 

Where'd the quotes go??  Oh, right, xargs eats them!

imadev:~$ group=$'foo\nbar\n"hi mom"three quotes"\n'
imadev:~$ xargs printf '<%s> ' <<< "$group"
xargs: missing quote?: quotes

So, apart from "xargs doesn't have a -d option" and "xargs without a -d
option can't handle filenames", sure, xargs is awesome!  



Re: Feature Request - Allow mapfile to handle NUL-delimited data

2011-05-19 Thread Maarten Billemont
On 13 May 2011, at 20:07, DJ Mills wrote:

> A -0 option, or even an option to use a different field separator, would be
> an
> excellent feature for mapfile.  Currently, of course, you can use:
> 
> while IFS= read -rd '' file; do array+=("$file"); done
> 
> mapfile is considerably faster, however, and I think this would be quite
> handy.

seconded.  I'm not sure why it only works for lines.  Sure, on the shell data 
is often line-based, but more often than that, line-based parsing is bad and 
should be done with a safe delimiter rather than \n instead.


Re: Shell case statements

2011-05-19 Thread Eric Blake
[adding bug-bash]

On 05/16/2011 07:23 PM, Wayne Pollock wrote:
> (While cleaning up the standard for case statement, consider that it is 
> currently
> unspecified what should happen if an error occurs during the expansion of the
> patterns; as expansions may have side-effects, when an error occurs on one
> expansion, should the following patterns be expanded anyway?  Does it depend 
> on
> the error?  It seems reasonable to me that any errors should immediately 
> terminate
> the case statement.)

Well, that's rather all over the place, but yes, it does seem like bash
was the buggiest of the lot, compared to other shells.  Interactively, I
tested:

readonly x=1
case 1 in $((x++)) ) echo hi1 ;; *) echo hi2; esac
echo $x.$?

bash 4.1 printed:
bash: x: readonly variable
hi1
1.0
which means it matched '1' to $((x++)) before reporting the failure
assign to x, and the case statement succeeded.  Changing the first "1"
to any other string printed hi2  (the * case).

zsh printed:
zsh: read-only variable: x
1.0
which means it aborted the case statement before executing any clauses,
but left $? at 0.

ksh printed:
ksh: x: is read only
1.1
which means that both the case statement was aborted, and $? was impacted.

dash printed:
dash: arithmetic expression: expecting primary: "x++"
1.2
so it was like ksh other than choice of error status.

-- 
Eric Blake   ebl...@redhat.com+1-801-349-2682
Libvirt virtualization library http://libvirt.org



signature.asc
Description: OpenPGP digital signature