LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 08-21-2007, 09:13 AM   #1
rejeep
Member
 
Registered: Mar 2007
Distribution: Gentoo
Posts: 49

Rep: Reputation: 15
Bash function return


Hi!

This is a function I have (modified with only the necessary parts):
Code:
#!/bin/bash

function temp
{
	find . -name "*.conf" -type f -exec grep "Word" {} \; |
	while read a b; do
		if [ $b == $1 ]; then
			return 0
		fi
	done
	
	return 1
}

if temp "none"; then
	echo "Yes"
else
	echo "No"
fi
This script will never return 0 since the pipe will create a new shell.

How can I solve this?
 
Old 08-21-2007, 09:56 AM   #2
mjones490
Member
 
Registered: Sep 2005
Distribution: LFS
Posts: 60

Rep: Reputation: 22
Using the back-quote, you can capture the standard out of a command into a variable, like this:

Code:
I=`wc my_doc.txt`
echo $I
The script would call wc, which would count the words/bytes/etc. in my_doc.txt, and print the results to standard out. Those results would then get stored in I.

Maybe you can somehow utilize back-quotes for your problem.
 
Old 08-21-2007, 10:18 AM   #3
rejeep
Member
 
Registered: Mar 2007
Distribution: Gentoo
Posts: 49

Original Poster
Rep: Reputation: 15
I did try that. But I get "ambiguous redirect" then.
Code:
#!/bin/bash

function temp
{
	var=`find . -name "*.conf" -type f -exec grep "Word" {} \;`

	while read a b; do
		if [ $b == $1 ]; then
			return 0
		fi
	done < $var
	
	return 1
}

if temp "none"; then
	echo "Yes"
else
	echo "No"
fi
I can print out var though! I get a space separated list then.
 
Old 08-22-2007, 04:29 AM   #4
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,453

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Quote:
This script will never return 0 since the pipe will create a new shell.
Probably I don't understand exactly what do you mean, but the script's exit code is 0 and the output of the function is always 1, because of
Code:
      return 1
or do I not see correctly?

Edit: uh... sorry, I was really confused (at this time in the morning) return 0 if the condition is true... sorry... mumble mumble...

Last edited by colucix; 08-22-2007 at 04:34 AM. Reason: beacuse obviously I was still sleepin'
 
Old 08-22-2007, 07:01 AM   #5
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,453

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Ok, now I am awake! Indeed my first guess was not really wrong: when doing -exec and opening a new subshell the return command does not return control to the script, but to the parent process (please, someone help me to clarify...) and the remaining commands inside the function are executed. In this case the statement
Code:
return 1
I have not a robust solution to workaround this issue, except a completely different algorithm, but for debugging purposes you may consider to launch your script as in
Code:
bash -x thescript.sh
or put
Code:
#!/bin/bash -x
as first line in the script. This will output the execution flow. Also consider to use -ok instead of -exec if you want to see which file is being processed (and answer yes or y when the shell prompts you for confirmation). Hope this will help. Cheers!
 
Old 08-22-2007, 08:01 AM   #6
rejeep
Member
 
Registered: Mar 2007
Distribution: Gentoo
Posts: 49

Original Poster
Rep: Reputation: 15
Process substitution was the right answer:
Code:
while read; do
   ...
done < <(find)
Thanks!
 
Old 08-22-2007, 08:32 AM   #7
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,453

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Very good! The shell is always full of surprises!
 
Old 08-23-2007, 02:44 AM   #8
fvu
LQ Newbie
 
Registered: Nov 2006
Distribution: Ubuntu 7.10
Posts: 28

Rep: Reputation: 15
The problem is that a PIPED `while-read' loop starts a subshell. This also causes variables introduced within the while-read loop to disappear. For example:
Code:
#!/bin/bash
echo nothing | while read line; do
    foo=bar
    echo foo1: $foo
done
echo foo2: $foo

# Example output:
# foo1: bar
# foo2:
Solution is to rewrite the script as a REDIRECTED `while-read' loop. For example, using process substitution:

Code:
#!/bin/bash
while read line; do
    foo=bar
    echo foo1: $foo
done < <(echo nothing)
echo foo2: $foo

# Example output:
# foo1: bar
# foo2: bar
See also:
http://fvue.nl/wiki/Bash:_Piped_%60w...tarts_subshell

Freddy Vulto
http://fvue.nl
 
Old 08-23-2007, 08:20 AM   #9
rejeep
Member
 
Registered: Mar 2007
Distribution: Gentoo
Posts: 49

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by colucix View Post
The shell is always full of surprises!
This is very true!!!

Quote:
Originally Posted by fvu View Post
Solution is to rewrite the script as a REDIRECTED `while-read' loop.
Thanks for the explanation!

Though I have one more question about it.
Why don't this script print out the last letter?
Code:
#!/bin/bash

var="a,c,d,e,b"

while read -d , foo; do
        echo $foo
done < <(echo $var)
Output is:
Quote:
a
c
d
e

Last edited by rejeep; 08-23-2007 at 08:57 AM.
 
Old 08-23-2007, 11:40 AM   #10
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,453

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Because when reading with -d <delimiter> the read command expects the <delimiter> at the end of input string. So, when reading "a," "c," "d," "e," the condition is true and the statement inside the while loop is executed. When reading "b" the condition is false.
Indeed the -d option is useful when reading multi-line input
Code:
-d delim
   The first character of delim is used to  terminate  the  input
   line, rather than newline.
You can verify this, by simply adding a "," after "b" in $var and - as usual - by executing with
Code:
bash -x
 
Old 08-23-2007, 11:49 AM   #11
rejeep
Member
 
Registered: Mar 2007
Distribution: Gentoo
Posts: 49

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by colucix View Post
You can verify this, by simply adding a "," after "b" in $var
Isn't there anyway else than that so solve it since var is user input?

Sure I can do:
Code:
done < <(echo "$var,")
But it feels like there should be a better way!
 
Old 08-23-2007, 01:10 PM   #12
colucix
Moderator
 
Registered: Sep 2003
Location: Bologna
Distribution: CentOS 6.5 OpenSuSE 12.3
Posts: 10,453

Rep: Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941Reputation: 1941
Using gawk?
Code:
#!/bin/bash

var="a,c,d,e,b"

echo $var | gawk -F, '{for (i=1; i<=NF; i++) print $i}'
You asked!
 
Old 08-23-2007, 01:38 PM   #13
rejeep
Member
 
Registered: Mar 2007
Distribution: Gentoo
Posts: 49

Original Poster
Rep: Reputation: 15
Quote:
Originally Posted by colucix View Post
Using gawk?
Code:
#!/bin/bash

var="a,c,d,e,b"

echo $var | gawk -F, '{for (i=1; i<=NF; i++) print $i}'
You asked!
Lol... I can settle with the first method! =)

Thanks!
 
Old 08-23-2007, 01:46 PM   #14
fvu
LQ Newbie
 
Registered: Nov 2006
Distribution: Ubuntu 7.10
Posts: 28

Rep: Reputation: 15
You can set the IFS variable (Internal Field Separator) to a comma, if you use a for-loop:

Code:
#!/bin/bash

OIFS=$IFS; IFS=,  # Backup and set new IFS
var="a,c,d,e,b"
for foo in $var; do
        echo "foo: $foo"
done
IFS=$OIFS  # Restore IFS

# Example output:
# foo: a
# foo: c
# foo: d
# foo: e
# foo: b
Within a `while'-loop it looks like this:

Code:
#!/bin/bash

var=a,c,d,e,b

while read; do
   echo REPLY: $REPLY
   OIFS=$IFS; IFS=,
   for v in $REPLY; do
      echo v: $v
   done
   IFS=$OIFS
done < <(echo $var)

# Example output:
# REPLY: a,c,d,e,b
# v: a
# v: c
# v: d
# v: e
# v: b
See also:
http://fvue.nl/wiki/Bash:_Parsing_lines


Freddy Vulto
http://fvue.nl

Last edited by fvu; 08-24-2007 at 02:05 AM. Reason: Removed unnecessary redirect at end of for-loop. Added for-loop within while-loop.
 
Old 08-24-2007, 02:32 AM   #15
fvu
LQ Newbie
 
Registered: Nov 2006
Distribution: Ubuntu 7.10
Posts: 28

Rep: Reputation: 15
You can also use bash `Parameter expansion' to make sure $var ends with a comma:

${var%,},

`${var%,}' removes a possible comma at the end of $var -- so with an additional `,' we can trust $var to always end with a comma.

Code:
#!/bin/bash

var=a,b,c

while read -d , ; do
   echo REPLY: $REPLY
done < <(echo ${var%,},)

# Example output:
# REPLY: a
# REPLY: b
# REPLY: c
See also: Shell Parameter Expansion

Freddy Vulto
http://fvue.nl
 
  


Reply


Thread Tools Search this Thread
Search this Thread:

Advanced Search

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 Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
How can I get the return value of a function in a shellscript? [KIA]aze Programming 8 07-05-2007 08:18 AM
return value of function in script ramesh_manu Red Hat 1 02-18-2007 01:05 PM
getting the return value from a thread start function cynthia_thomas Programming 1 02-18-2006 08:23 AM
using return in recursive function hubabuba Programming 9 10-10-2005 09:59 AM
can a function return a string? hubabuba Programming 13 03-06-2005 02:51 PM


All times are GMT -5. The time now is 10:41 AM.

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration