Package: zsh
Version: 4.3.0-dev-5-1
Severity: normal

it is fiendishly difficult to write a portable shell version of xargs
that can take a shell function as an argument and that follows good
programming practices involving reentrance, namespaces, signals, exit
codes, etc.

what i would propose, if i thought that both the bash and zsh
development teams would be interested in them, would be about 10
improvements, including a portable built in xargs and xargs -0 from
the get-go.

but i will limit my ambitions and propose a truly raw read -r.  this
is because i think that both teams would want that.

here is why this is important.  consider:

        find ... -xdev |
                grep -v \\.svn/ |
                xargs ... grep apple

xargs is bad for this because grep cannot print the filename properly.
you could use xargs and call $0, but that's inefficient and doesn't
handle non-exported variables.

you might think that a shell loop can achieve the same effect, but
consider what many people will do:

        find ... -xdev |
                grep -v \\.svn/ |
                while read -r i
                do
                        grep apple "$i"
                done

this will not get all filenames.  read -r does not do a raw read -- to
see what i mean try leading whitespace in the input.

there are other problems with it also, such as it being difficult to
know how to do the equivalent of xargs -0.  it gets complicated to fix
unless you hit on the IFS idea, and even then it is fiendish wrt
reentrance etc.

lots of people probably do their backups using such a loop.

my IFS solution works for me, but i think that the user shouldn't have
to figure out that it is necessary or do comprehensive testing.

imho there should be an xargs/xargs -0 built into both zsh and bash to
make it maximally easy, but a good start would be a truly raw read.

below is my solution and comments.  all of my shell code has to work
in both bash and zsh.

======

#       #IFS='' works in bash but it fails as \\\ -> \\ in zsh

readvari () {   #use this instead of read or read -r
#or if not too slow: while . $0 readvari
        IFS=$'\n' read -r "$1"
}

mapcar () {             mapcarhow normal "$@" ;}
gather () {             mapcarhow gather "$@" ;}
mapcarnospace () {      mapcarhow nospace "$@" ;}

mapcarhow () {
        local how="${1:?}"; shift
        #will local work?
        local mchargs=''
        #if you do mapcar aaaaa where aaaaa does another mapcar to dev null
        #it works whether the following local is declared or not
        #local readspecialspecial
        while readvari readspecialspecial
        do
                case $how in
                nospace)        "$@""$readspecialspecial" ;;
                normal)         "$@" "$readspecialspecial" ;;
                gather)         mchargs="$mchargs \"$readspecialspecial\"" ;;
                esac
        done
        case $how in
        gather)         eval "$@"$mchargs ;;
        esac
}

#this can do xmapcar
mapcarawk () {  #!this works perfectly but is even slower than below
        awk '{c="'"$@"'" " " "'\''" $0 "'\''" ; system(c)}'
}

readraw () {    #read one line and print it, returning nonzero for EOF
#head -1 does not exit nonzero for EOF.
        line
        #works but cat ... | mapcar is different from mapcar
        #awk 'BEGIN { s="" ; a=getline s ; if (a) print s ; exit 1-a }'
#line works with ^D but read does not, at least when called by mapcar1.
#       IFS=$'\n' read -r
#       #zsh and bash
#       echo -E "$REPLY"
}

#       #read -d `echo -e '\0'`
#       #and IFS='\0' read ... do not work.
#       #IFS='\0\0\0' read seems not to work.
#       #mawk might not be able to do this
#       awk 'BEGIN { RS="\000" ...

#works but has offensive inband code.  designed for while mapcar1 ...:
#still has problems: maybe some weird filenames, and it stops on error (which
#is ironic and sucky given bash's tendency to continue on ^C)
#mapcar1 () {
#       #there seem to be several bugs in the shells that prevent this from 
being
#       #easy.  test cannot compare to a string with \n easily, read isn't
#       #portable, bash cannot do local a=`readraw || r=1` or even local
#       #a=`readraw || return 1`, read -r is not truly raw in either bash or
#       #zsh.  `...` cannot set variables since it is apparently a subshell.
#       #etc.  this also makes xmapcar difficult.
#       #
#       #maybe while
#       #readraw > $one-line-tmp-file would work, but ... the file system?
#       
#       #even this seems not to work:
#       #local line=`readraw`
#       #local r=$?
#       #if [ "$r" = 0 ]
#       #then
#       #fi
#       #return $r
#       
#       local gensym=/dev/null/special--nonexistent--mapcar1
#       #readraw prints \n on EOF, so we compare to this
#       local kludge=`echocode "\n$gensym"`
#       local a=`readraw || echo -n $gensym`
#       if [ "$a" = "$kludge" ]
#       then
#               return 1
#       else
#               mapcarinside "$a" "$@"
#       fi
#}

======

thanks.


-- System Information:
Debian Release: 3.1
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)

Versions of packages zsh depends on:
ii  debconf [debconf-2.0]         1.4.30.13  Debian configuration management sy
ii  libc6                         2.3.6-7    GNU C Library: Shared libraries
ii  libncurses5                   5.5-1.1    Shared libraries for terminal hand

Versions of packages zsh recommends:
ii  libcap1                    1:1.10-14     support for getting/setting POSIX.
ii  libpcre3                   4.5-1.2sarge1 Perl 5 Compatible Regular Expressi

-- debconf information:
* zsh/rcmove:


-- 
To UNSUBSCRIBE, email to [EMAIL PROTECTED]
with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]

Reply via email to