Ubuntu Forums ubuntu.com - launchpad.net - ubuntu help  

Go Back   Ubuntu Forums > The Ubuntu Forum Community > Other Community Discussions > Development & Programming > Programming Talk
Register Reset Password Forum Help Forum Council Search Today's Posts Mark Forums Read

Programming Talk
This forum is for all programming questions.
The questions do not have to be directly related to Ubuntu and any programming language is allowed.

 
Thread Tools Display Modes
Old December 3rd, 2006   #1
Georges
5 Cups of Ubuntu
 
Join Date: Apr 2005
Location: Luxembourg
Beans: 44
ksh vs bash: setting variable in piped loops are lost

I'm a long time unix (not linux) programmer, mainly shell scripts.
Unix does not know about bash, but rather ksh or sh.

So I often build stuff like this:
Code:
n=0
du | sort -n | while read size dir
do
  if [ "$size" -gt 100000 ]
  then
    n=$((n+1))
  fi
done
echo "Found $n too big files"
the question is not how to reformulate this differently using awk or perl.
The question is:

in ksh this script returns the correct value
in bash it always returns 0

This is because in ksh the last command in the pipe runs in the current process, whereas in bash the first command runs in the current proces. Result: the modified variables are lost.

I'm still puzzled that his is the case and that nobody really cares about.
Maybe I'm missing the point and there is some simple environment variable or other setting to change to enable ksh compatible behaviour.

Georges
Georges is offline   Reply With Quote
Old December 3rd, 2006   #2
mssever
I Ubuntu, Therefore, I Am
 
mssever's Avatar
 
Join Date: Jun 2006
Location: 대전, Korea
Beans: 3,447
Ubuntu 8.10 Intrepid Ibex
Send a message via AIM to mssever Send a message via Yahoo to mssever Send a message via Skype™ to mssever
Re: ksh vs bash: setting variable in piped loops are lost

Quote:
Originally Posted by Georges View Post
I'm a long time unix (not linux) programmer, mainly shell scripts.
Unix does not know about bash, but rather ksh or sh.

So I often build stuff like this:
Code:
n=0
du | sort -n | while read size dir
do
  if [ "$size" -gt 100000 ]
  then
    n=$((n+1))
  fi
done
echo "Found $n too big files"
the question is not how to reformulate this differently using awk or perl.
The question is:

in ksh this script returns the correct value
in bash it always returns 0

This is because in ksh the last command in the pipe runs in the current process, whereas in bash the first command runs in the current proces. Result: the modified variables are lost.

I'm still puzzled that his is the case and that nobody really cares about.
Maybe I'm missing the point and there is some simple environment variable or other setting to change to enable ksh compatible behaviour.

Georges
I guess that's something I've never really tried before--maybe because I've always used bash. I don't think that the bash devs care a whole lot about ksh, but I understand that zsh is nearly 100% compatible with ksh--plus a bunch of added features. You might be interested in it. It's available from the main repo. I haven't used it much, but then, bash does everything I need...

I suppose a bash kludge could be to use tmp files rather than a pipeline, but that isn't very elegant.
__________________
What's a blub programmer?         Registered Linux user #419974
My projects:
Net Responsibility -- Internet accountability software for Linux
BadgeEntry -- Track attendance for children's events
mssever is offline   Reply With Quote
Old December 4th, 2006   #3
Georges
5 Cups of Ubuntu
 
Join Date: Apr 2005
Location: Luxembourg
Beans: 44
Re: ksh vs bash: setting variable in piped loops are lost

yes, "apt-get install ksh" is a solution too.

So you never use longer pipe constructs with loops etc?
That's the real power of shell programming, else one could as well use perl.

zsh also behaves correctly.

Only bash is different. The developers probably think they can reinvent the wheel in square form. Do you think there is any chance that a bug report will help?
Georges is offline   Reply With Quote
Old December 4th, 2006   #4
Arndt
100% Pure Ubuntu
 
Join Date: May 2006
Beans: 852
Re: ksh vs bash: setting variable in piped loops are lost

Quote:
Originally Posted by Georges View Post
yes, "apt-get install ksh" is a solution too.

So you never use longer pipe constructs with loops etc?
That's the real power of shell programming, else one could as well use perl.

zsh also behaves correctly.

Only bash is different. The developers probably think they can reinvent the wheel in square form. Do you think there is any chance that a bug report will help?
Googling for "bash pipe subprocesses order" shows that the question has been asked before, but I couldn't find what the bash developers' official stand is.
Arndt is offline   Reply With Quote
Old October 13th, 2008   #5
malagant
First Cup of Ubuntu
 
Join Date: Mar 2007
Beans: 1
Re: ksh vs bash: setting variable in piped loops are lost

I know this is a dead thread but I wanted to add something in case someone comes looking at this for a solution. My thanks as always to the mksh team. The solution involves (m)ksh co-processes. Sounds like you may be able to do something similar with bash using named pipe pairs (one for read, one for write) if you do a little research in that area.

This works in mksh 35b:

Code:
n=0
du | sort -n |& 
while read -p size dir
 
do
  if [ "$size" -gt 1000 ]
  then
    n=$((n+1))
  fi
done
echo "Found $n too big files"
Basically this is straight from the mksh man page. mksh is the successor to pdksh and several times smaller and faster than bash or zsh. Think of it as a step up from dash at almost 100% POSIX compliance. If you come from a Solaris, HP-UX or AIX shop and are used to ksh but miss the nice touches of the newer shells then you should give mksh a try. As a bonus it is UTF aware (zsh isn't nor is bash without add-ons, I believe) and is also actively being developed.
malagant is offline   Reply With Quote
Old October 13th, 2008   #6
Georges
5 Cups of Ubuntu
 
Join Date: Apr 2005
Location: Luxembourg
Beans: 44
Re: ksh vs bash: setting variable in piped loops are lost

that's like a kludge with temporary files we mentioned earlier.
And there are no co-processes in bash either.
How can this be the default shell in linux. It lacks several great inventions which make unix stand out.

Thanks for the hint on mksh, I will give it a try (setting it as default shell).

Georges
Georges is offline   Reply With Quote
Old November 12th, 2008   #7
mirabilos
Spilled the Beans
 
mirabilos's Avatar
 
Join Date: Nov 2008
Beans: 13
Re: ksh vs bash: setting variable in piped loops are lost

Quote:
Originally Posted by malagant View Post
My thanks as always to the mksh team.
That would be me thanks.

Quote:
Originally Posted by malagant View Post
Code:
du | sort -n |&
Basically this is straight from the mksh man page.
Actually, in your case, this would be better:

Code:
(du | sort -n) |&
I seem to recall, though, that these parenthesēs are implicit in recent versions of mksh. (These also build on a fair larger number of platforms – ULTRIX, OSF/1, QNX, … – and with much more compilers than just gcc.)

Last edited by mirabilos; November 12th, 2008 at 05:32 PM.. Reason: typo
mirabilos is offline   Reply With Quote
Old November 12th, 2008   #8
eightmillion
Dipped in Ubuntu
 
eightmillion's Avatar
 
Join Date: Jul 2008
Beans: 565
Re: ksh vs bash: setting variable in piped loops are lost

I just spent 15 minutes trying to do this in pure bash before realizing that this thread is nearly 2 years old. Anyway, here's what I came up with. It's not pretty, but it works.

Code:
#!/bin/bash
n=0;a=0;x=0
for line in `du | sort -n`;do
if [ $line -eq $line 2> /dev/null ];then
 size[$n]=$line
 n=$(($n+1))
fi
done
while [ $x -lt ${#size[*]} ];do
  if [ ${size[$x]} -gt 100000 ];then
    a=$(($a+1))
  fi
  x=$(($x+1))
done
echo "Found $a too big files"
exit
__________________
Code:
clear;while read x;do for((i=0;i<${#x};i++));do printf "${x:$i:1}";sleep .015;done;echo;done< <(awk '/[<\/li>,<ul>]<li>/{gsub(/<[^<]*?\/?>|\[.*\]|\(.*\)/,"");$1=$1;print}' <(wget -q -O- http://bit.ly/zDZ1I))
eightmillion is offline   Reply With Quote
Old November 13th, 2008   #9
Cracauer
Dipped in Ubuntu
 
Cracauer's Avatar
 
Join Date: Sep 2007
Location: Cambridge, MA
Beans: 534
Re: ksh vs bash: setting variable in piped loops are lost

Unfortunately bash is plain and simply correct when it comes to bourne shell script according to POSIX. You got the pipe, you are in a child process and nothing you do influences the parent process.

This is really annoying since it pretty much disables all sane ways to deal with filenames that contain any number of wired characters, sequences of multiple spaces one after another etc.

You never can use
find . ... | while read foo ; echo $foo ; do

Nor can you use
find . -print0 | xargs -0 ...
invoking anything under the script's control that would allow you to count.

The only way to make use of this in the loop solution is to return everything you want for status by echoing them and putting the whole loop into $(...). If you need stdout for other purposes inside the loop you gotta start placing a bunch of bloddy `1>&3) | ... 3>&1 | grep`.
Cracauer is offline   Reply With Quote
Old November 13th, 2008   #10
geirha
I Ubuntu, Therefore, I Am
 
Join Date: Feb 2007
Beans: 3,453
Ubuntu 9.04 Jaunty Jackalope
Re: ksh vs bash: setting variable in piped loops are lost

I guess the prettiest way to handle it in bash would be something like this:
Code:
#!/bin/bash
exec 3< <(du | sort -n)  

n=0
while read size dir; do
  [ $size -gt 1000 ] && ((n++))
done <&3
exec 3<&-

echo "Found $n too big files"
geirha is offline   Reply With Quote

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 06:18 AM.


vBulletin ©2000 - 2010, Jelsoft Enterprises Ltd. Ubuntu Logo, Ubuntu and Canonical © Canonical Ltd. Tango Icons © Tango Desktop Project. lingonberry