bash: request for a way to return variables to the parent of a subshell

2008-07-22 Thread Richard Neill
At the moment, variables set within a subshell can never be accessed by 
the parent script. This is true, even for an implicit subshell such as 
caused by read.


For example, consider the following (slightly contrived example)


touch example-file
ls -l | while read LINE ; do
if [[ $LINE =~ example-file ]]; then
MATCH=true; [a]
echo Match-1
fi ;
done
if [ $MATCH == true ] ;then [b]
echo Match-2
fi
---


This prints Match-1, but does not print Match-2.

The only way to get data out of the read-subshell is by something like 
exit 2, and looking at $?





It's already possible to export a variable into the environment, and for 
subshells to inherit variables from the main script. Do we need a new 
keyword to achieve the reverse? Is there any way to make sure that 
variables defined at [a] can be made to still exist at [b] ?



Thanks,

Richard






Re: bash: request for a way to return variables to the parent of a subshell

2008-07-22 Thread Chris F.A. Johnson
On 2008-07-23, Richard Neill wrote:
 At the moment, variables set within a subshell can never be accessed by 
 the parent script. This is true, even for an implicit subshell such as 
 caused by read.

The subshell is caused by the ipe, not by read.

 For example, consider the following (slightly contrived example)

 
 touch example-file
 ls -l | while read LINE ; do
   if [[ $LINE =~ example-file ]]; then
   MATCH=true; [a]
   echo Match-1
   fi ;
 done
 if [ $MATCH == true ] ;then [b]
   echo Match-2
 fi
 ---


 This prints Match-1, but does not print Match-2.

touch example-file
ls -l | {
   while read LINE ; do
 if [[ $LINE =~ example-file ]]; then
MATCH=true;
echo Match-1
 fi
   done
   if [ $MATCH == true ] ;then
   echo Match-2
   fi
}

-- 
   Chris F.A. Johnson, webmaster http://Woodbine-Gerrard.com
   ===
   Author:
   Shell Scripting Recipes: A Problem-Solution Approach (2005, Apress)


Re: bash: request for a way to return variables to the parent of a subshell

2008-07-22 Thread Eric Blake

-BEGIN PGP SIGNED MESSAGE-
Hash: SHA1

According to Richard Neill on 7/22/2008 8:04 PM:
| This prints Match-1, but does not print Match-2.
|
| The only way to get data out of the read-subshell is by something like
| exit 2, and looking at $?

You can also use files.  The position within a seekable file is preserved
from child to parent, but once you are using files, you might as well go
with the file contents.

| It's already possible to export a variable into the environment, and for
| subshells to inherit variables from the main script. Do we need a new
| keyword to achieve the reverse? Is there any way to make sure that
| variables defined at [a] can be made to still exist at [b] ?

A new keyword is insufficient.  This is something that is fundamentally
not provided by Unix systems - short of using the file system, there
really isn't a way to pass arbitrary information from a child process back
to the parent.

But maybe the 'source' builtin is what you are looking for, to execute a
script in the same context rather than forking off a child.

- --
Don't work too hard, make some time for fun as well!

Eric Blake [EMAIL PROTECTED]
-BEGIN PGP SIGNATURE-
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iEYEARECAAYFAkiGmkYACgkQ84KuGfSFAYAFpQCeMsQjKYSjL6iQuzbwBO0muYDY
QVYAoIxIozi5kQvkOSC0oBSUrJYRQcZJ
=sZ1V
-END PGP SIGNATURE-




Re: bash: request for a way to return variables to the parent of a subshell

2008-07-22 Thread Richard Neill

Dear Eric,

Thank you for your helpful answer. I'd understood that bash *doesn't* 
pass info back from the child to the parent, but I didn't realise that 
it was fundamentally *impossible* to do in Unix. I guess that tempfiles 
would do it - though that's rather ugly.


Is there any way to use read to iterate over its standard input 
without creating a subshell?  If it's of interest, the actual part of 
the script I use is below - the aim is to parse the output of ffmpeg 
-formats to see whether certain codecs are supported by that build.


Regards,

Richard





--


#Does this version of FFMPEG support the relevant file format?  Exit
#if not. Arguments:  $1='file' or 'codec';  $2='E','encode' or
# 'D','decode', $3=format/codec_name
#Example:check_ffmpeg_format file D ogg

#The output of `ffmpeg -formats`  has section headings such as
#File formats, and each section is delimited by a blank line.

#The first part of the line contains letters DEA(etc) depending
#on whether the codec/file is supported
#for reading (decoding) and/or writing (encoding).

function check_ffmpeg_format_support(){ .
local filecodec=$1
local decodeencode=$2
local filecodec_name=$3

if [ $filecodec == 'file' ];then
local start_trigger='File formats:'
local end_trigger=''
local terminator='\ +'
local filecodec_txt='file format'
else
local start_trigger='Codecs:'
local end_trigger=''
local terminator='$'
local filecodec_txt='with codec'
fi

if [ $decodeencode == 'decode' -o $decodeencode == 'D' ];then   
local decodeencode='D[A-Z ]*'
local decodeencode_txt='decoding'
else
local decodeencode='[A-Z ]?E[A-Z ]*'
local decodeencode_txt='encoding'
fi

  local matchme='^\ *'$decodeencode'\ +'$filecodec_name'\ *'$terminator

local relevant=false


#Warning: this pipe has the effect of a subshell. Variables are
#set inside the pipeline, and cannot be accessed outside it.
#Search between trigger points.

ffmpeg -formats 2/dev/null | while read line ; do
if [[ $line =~ $start_trigger ]]; then
relevant=true
fi
if [[ $line == $end_trigger ]]; then
relevant=false
fi
if [ $relevant == true ];then
if [[ $line =~ $matchme ]];then #Regex match.
exit 2  
fi
#Exit the '| while read...'  part, and return $? so we
#know the result.
fi
done

if [ $? != 2 ]; then
echo -e ERROR: the installed version of 'ffmpeg' was built
without support enabled for $decodeencode_txt $filecodec_txt
'$filecodec_name'.\n
 exit 1
fi
}

--




Eric Blake wrote:

According to Richard Neill on 7/22/2008 8:04 PM:
| This prints Match-1, but does not print Match-2.
|
| The only way to get data out of the read-subshell is by something like
| exit 2, and looking at $?

You can also use files.  The position within a seekable file is preserved
from child to parent, but once you are using files, you might as well go
with the file contents.

| It's already possible to export a variable into the environment, and for
| subshells to inherit variables from the main script. Do we need a new
| keyword to achieve the reverse? Is there any way to make sure that
| variables defined at [a] can be made to still exist at [b] ?

A new keyword is insufficient.  This is something that is fundamentally
not provided by Unix systems - short of using the file system, there
really isn't a way to pass arbitrary information from a child process back
to the parent.

But maybe the 'source' builtin is what you are looking for, to execute a
script in the same context rather than forking off a child.






Re: bash: request for a way to return variables to the parent of a subshell

2008-07-22 Thread Paul Jarc
Richard Neill [EMAIL PROTECTED] wrote:
 the aim is to parse the output of ffmpeg -formats to see whether
 certain codecs are supported by that build.

I'd use something like:
while read line; do
  ...
done  (ffmpeg -formats 2/dev/null)

That puts ffmpeg into a subshell instead of read.


paul




Re: bash: request for a way to return variables to the parent of a subshell

2008-07-22 Thread Richard Neill
Thank you. That's a really neat solution - and it would never have 
occurred to me. I always think from left to right!


Richard



Paul Jarc wrote:

Richard Neill [EMAIL PROTECTED] wrote:

the aim is to parse the output of ffmpeg -formats to see whether
certain codecs are supported by that build.


I'd use something like:
while read line; do
  ...
done  (ffmpeg -formats 2/dev/null)

That puts ffmpeg into a subshell instead of read.


paul