Re: return from function doesn't work when used in tail of pipeline

2010-08-12 Thread Greg Wooledge
On Thu, Aug 12, 2010 at 01:23:20PM +1000, Martin Schwenke wrote:
> Description:
>   I don't believe that the following behaviour is sensible or
>   matches the standard/documentation:
> 
>   $ f () {   { echo 1 ; echo 2 ; } | while read line ; do echo $line ; 
> return 0 ; done ; echo foo ; return 1 ; }
>   $ f
>   1
>   foo
>   $ echo $?
>   1
> 
>   I expect f to return 0 from within the loop because a function
>   is executing.
> 
>   I know the return 0 is in a subprocess at the end of a
>   pipeline... but that whole pipeline is running within a
>   function.

You already know the reason it behaves the way it does, so I'm not
quite sure what answer you expect to receive.  It's not a bug -- it's
the normal behavior of every shell.

imadev:~$ sh -c 'f() { (return 0); return 1; }; f; echo $?'
1
imadev:~$ ksh -c 'f() { (return 0); return 1; }; f; echo $?'
1
imadev:~$ bash -c 'f() { (return 0); return 1; }; f; echo $?'
1

A return that's run in a subshell doesn't cause the parent shell to
return.

>   In
>   general I expect to be able to pipe the output of a command
>   into a loop and have the loop read lines until some condition
>   occurs, at which point my function returns.

Ah, a real question! :)

Use a process substitution in bash:

f() {
  while IFS= read -r somevar; do
[[ $somevar = *quit* ]] && return 0
printf '%s\n' "$somevar"
  done < <(grep foo bar)
  return 1
}

>   This could
>   obviously be done using a out=$(cmd) subprocess... except in
>   the case where cmd can block before producing all of its
>   output.  Hence, the above seems convenient.

The process substitution doesn't require cmd to finish before it
starts producing data.  It's equivalent to a pipeline, except that
the reader doesn't need to be in a subshell.



Re: read -d'' -n1

2010-08-12 Thread Greg Wooledge
> On Thu, Aug 12, 2010 at 1:46 PM, Jan Schampera  wrote:
> >> while read -d'' -n1 ch; do

On Thu, Aug 12, 2010 at 01:50:34PM +0800, Sharuzzaman Ahmat Raslan wrote:
> Which part is the mistake, and what is the solution?

If you want the argument of -d to be an empty string, you have to separate
the empty string argument from the -d with some whitespace:

  read -d '' -n1 ch

Otherwise, -d'' is exactly the same as -d (the '' goes away entirely),
and read tries to use the -n1 as the argument of -d.  Since -d only
takes a single character, the - becomes the delimiter.



Re: Wrong prompt and incorrect parsing if completion is used

2010-08-12 Thread Chet Ramey
On 8/9/10 12:02 PM, Egmont Koblinger wrote:
> Hello,
> 
> I've found a weird behavior.  In some circumstances, if I use TAB completion
> during typing a command line, the final command is parsed differently than
> if I typed it all along.
> 
> I'm on Ubuntu Lucid.  The bug described below occurs only if I use the
> bash-completion package (that is, I source /etc/bash_completion - it can be
> found at http://packages.ubuntu.com/lucid/bash-completion ).  However, the
> behavior suggests that probably it's a bug in bash itself, not the
> bash-completion package.

Maybe.  Before I take a closer look at this, what does running the
offending set of commands with `set -x' enabled show?

Chet

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/



PIPESTATUS always returns only a single element

2010-08-12 Thread lsteeger
Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc -I/usr/src/packages/BUILD/bash-4.1 
-L/usr/src/packages/BUILD/bash-4.1/../readline-6.1
Compilation CFLAGS:  -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' 
-DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-suse-linux-gnu' 
-DCONF_VENDOR='suse' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL 
-DHAVE_CONFIG_H   -I.  -I. -I./include -I./lib   -fmessage-length=0 -O2 -Wall 
-D_FORTIFY_SOURCE=2 -fstack-protector -funwind-tables 
-fasynchronous-unwind-tables -g  -D_GNU_SOURCE -DRECYCLES_PIDS -Wall -g 
-std=gnu89 -Wuninitialized -Wextra -Wno-unprototyped-calls -Wno-switch-enum 
-Wno-unused-variable -Wno-unused-parameter -ftree-loop-linear -pipe 
-fprofile-use
uname output: Linux russte14 2.6.31.12-0.2-desktop #1 SMP PREEMPT 2010-03-16 
21:25:39 +0100 x86_64 x86_64 x86_64 GNU/Linux
Machine Type: x86_64-suse-linux-gnu

Bash Version: 4.1
Patch Level: 7
Release Status: release

Description:
PIPESTATUS never shows more than 1 array element after executing a 
multiple command pipe

Repeat-By:
Execute the following script:

#!/bin/bash
#
# A script to test PIPESTATUS and pipefail
#
echo "   cmd: set +o pipefail"
echo "  pipe: ps -ef 2>&1 | grep "^\$USR" >/dev/null"
set +o pipefail
ps -ef 2>&1 | grep "^$USR" >/dev/null
echo "expect: PIPESTATUS = 1 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} \$? 
= $?"
echo
echo "   cmd: set -o pipefail"
echo "  pipe: ps -ef 2>&1 | grep "^\$USR" >/dev/null"
set -o pipefail
ps -ef 2>&1 | grep "^$USR" >/dev/null
echo "expect: PIPESTATUS = 1 0 \$? = 1; got: PIPESTATUS = ${PIPESTATUS[*]} \$? 
= $?"
echo
echo "  pipe: ps aux 2>&1 | grep "^\$USER" >/dev/null"
ps aux 2>&1 | grep "^$USER" >/dev/null
echo "expect: PIPESTATUS = 0 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} \$? 
= $?"
echo "expect: PIPESTATUS = 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} \$? = 
$?"
#
# End of script

None of the 'got' results 'expect'ing multiple PIPESTATUS results work.



Re: return from function doesn't work when used in tail of pipeline

2010-08-12 Thread Martin Schwenke
On Thu, 12 Aug 2010 08:16:21 -0400, Greg Wooledge 
wrote:

> You already know the reason it behaves the way it does, so I'm not
> quite sure what answer you expect to receive.  It's not a bug -- it's
> the normal behavior of every shell.
> 
> imadev:~$ sh -c 'f() { (return 0); return 1; }; f; echo $?'
> 1
> [...]
> A return that's run in a subshell doesn't cause the parent shell to
> return.

I want it to either obey the principle of least surprise or be more
clearly documented!  return is syntax so I expect it to do what its
documentation says it does...

I've been programming in shell for 20 years and this one surprised me.
I have a very strong Unix background and I clearly understand things
like not being able to set variables in subshells.  It also surprised
other people, with similar backgrounds, who I showed it to.  It is much
less obvious than many other shell subtleties.

There are some obvious exceptions to the strict Unix subprocess model in
shell programming (e.g. I can set a variable without exporting it and
see it in a subshell) and I expected this to be one of them.

Adding something like this to the documentation for return would
probably be enough:

  Note that many compound commands that might be used in a function
  cause subshells to be created.  In this subshells return will behave
  as though it is being used outside a function.

> Use a process substitution in bash:
> 
> f() {
>   while IFS= read -r somevar; do
> [[ $somevar = *quit* ]] && return 0
> printf '%s\n' "$somevar"
>   done < <(grep foo bar)
>   return 1
> }
[...] 
> The process substitution doesn't require cmd to finish before it
> starts producing data.  It's equivalent to a pipeline, except that
> the reader doesn't need to be in a subshell.

Thanks, I'll use that unless I can come up with something more
portable!  :-)

peace & happiness,
martin



Re: PIPESTATUS always returns only a single element

2010-08-12 Thread Chet Ramey
On 8/12/10 6:37 PM, lstee...@gmail.com wrote:

> Bash Version: 4.1
> Patch Level: 7
> Release Status: release
> 
> Description:
>   PIPESTATUS never shows more than 1 array element after executing a 
> multiple command pipe
> 
> Repeat-By:
>   Execute the following script:
> 
> #!/bin/bash
> #
> # A script to test PIPESTATUS and pipefail
> #
> echo "   cmd: set +o pipefail"
> echo "  pipe: ps -ef 2>&1 | grep "^\$USR" >/dev/null"
> set +o pipefail
> ps -ef 2>&1 | grep "^$USR" >/dev/null
> echo "expect: PIPESTATUS = 1 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} 
> \$? = $?"
> echo
> echo "   cmd: set -o pipefail"
> echo "  pipe: ps -ef 2>&1 | grep "^\$USR" >/dev/null"
> set -o pipefail
> ps -ef 2>&1 | grep "^$USR" >/dev/null
> echo "expect: PIPESTATUS = 1 0 \$? = 1; got: PIPESTATUS = ${PIPESTATUS[*]} 
> \$? = $?"
> echo
> echo "  pipe: ps aux 2>&1 | grep "^\$USER" >/dev/null"
> ps aux 2>&1 | grep "^$USER" >/dev/null
> echo "expect: PIPESTATUS = 0 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} 
> \$? = $?"
> echo "expect: PIPESTATUS = 0 \$? = 0; got: PIPESTATUS = ${PIPESTATUS[*]} \$? 
> = $?"
> #
> # End of script
> 
> None of the 'got' results 'expect'ing multiple PIPESTATUS results work.

Interesting.  I can't reproduce it.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/