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]