bash: request for a way to return variables to the parent of a subshell
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
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
-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
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
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
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