Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

calling a variable from another scope Not sure how to describe

60 views
Skip to first unread message

Jason Guto

unread,
Sep 22, 2017, 1:09:57 PM9/22/17
to
I am not sure how to describe my issue; however, I have created a variable, but I cannot access it. I believe this is due to scope or protection, and I am not sure if the 'file_content' variable should be global or just called from another location.

---CODE----
set dir "."
set out1 [glob *]

set file_ext "*.ameta"
set sort_out [lsort -dictionary $out1]

foreach line $sort_out {
if [file isfile $line] {
if [string match $file_ext $line] {
set file_open [open $line r]
set file_content [read $file_open]
close $file_open
}
puts $file_content
puts "$line test-1 IS A FILE"
} else {

}
}

exit
---CODE---

When ran - I get the following error at the 'puts $file_content' in first if statement. How can I access the 'file_content' from the second if statement?

Thank you

Gerald Lester

unread,
Sep 22, 2017, 1:54:21 PM9/22/17
to
No, it means that the condition of the inner if was false, so you never
set the variable!

Also, you should brace the expressions on the if commands to prevent
double substitutions. E.g. if {[string match $file_ext $line]} {

--
+----------------------------------------------------------------------+
| Gerald W. Lester, President, KNG Consulting LLC |
| Email: Gerald...@kng-consulting.net |
+----------------------------------------------------------------------+

Jason Guto

unread,
Sep 22, 2017, 3:06:15 PM9/22/17
to
Hi Gerald,
Thank you for your time and help. I am a little confused by your comments. If I move around some code for example:

-----code-----
set dir "."
set out1 [glob *]

set file_ext "*.ameta"
set sort_out [lsort -dictionary $out1]

foreach line $sort_out {
if [file isfile $line] {
if [string match $file_ext $line] {
set file_open [open $line r]
set file_content [read $file_open]
close $file_open
puts $file_content
}

puts "$line test-1 IS A FILE"
} else {
}
}

exit
----code-----

My application works as I need it; however, I need to be able to call the saved '$file_content' in the second if statement, since I am performing two if checks. (1) if the items is a file, and (2) is the file is a '.ameta' file.

Since I am teaching myself TCL and TCL/TK, and have no background in programming... I am open to suggestions.

Thank you

Gerald Lester

unread,
Sep 22, 2017, 3:57:46 PM9/22/17
to
On 09/22/2017 02:06 PM, Jason Guto wrote:
> On Friday, September 22, 2017 at 1:54:21 PM UTC-4, Gerald Lester wrote:
>> On 09/22/2017 12:08 PM, Jason Guto wrote:
>>> ...
>>> When ran - I get the following error at the 'puts $file_content' in first if statement. How can I access the 'file_content' from the second if statement?
>>
>> No, it means that the condition of the inner if was false, so you never
>> set the variable!
>>
>> Also, you should brace the expressions on the if commands to prevent
>> double substitutions. E.g. if {[string match $file_ext $line]} {
>>...
>
> Hi Gerald,
> Thank you for your time and help. I am a little confused by your comments. If I move around some code for example:
> ...

> My application works as I need it; however, I need to be able to call the saved '$file_content' in the second if statement, since I am performing two if checks. (1) if the items is a file, and (2) is the file is a '.ameta' file.
>
> Since I am teaching myself TCL and TCL/TK, and have no background in programming... I am open to suggestions.

Try running the following and see if you now understand:


#-----code-----
set dir "."
set out1 [glob -nocomplain *]

set file_ext "*.ameta"
set sort_out [lsort -dictionary $out1]

foreach line $sort_out {
if {[file isfile $line]} {
if {[string match $file_ext $line]} {
set file_open [open $line r]
set file_content [read $file_open]
close $file_open
puts $file_content
} else {
puts "$line does not match {$file_3xt}"
}

puts "$line test-1 IS A FILE"
} else {
puts "$line -- how would glob return me?"

Jason Guto

unread,
Sep 22, 2017, 4:28:25 PM9/22/17
to
Thank you again, I am currently working through this code, and trying to understand.

However, let me ask you this - how would I save the content of "file_content" to be able to access from another part of the application? The latter is what I am really trying to do/what I really need.

Thank you

Rich

unread,
Sep 22, 2017, 4:36:51 PM9/22/17
to
Jason Guto <jaso...@gmail.com> wrote:
> I am not sure how to describe my issue; however, I have created a
> variable, but I cannot access it. I believe this is due to scope or
> protection, and I am not sure if the 'file_content' variable should
> be global or just called from another location.
>
> ---CODE----
> set dir "."
> set out1 [glob *]
>
> set file_ext "*.ameta"
> set sort_out [lsort -dictionary $out1]
>

I added some line numbers below.

> foreach line $sort_out {
> if [file isfile $line] {
>(1) if [string match $file_ext $line] {
> set file_open [open $line r]
>(2) set file_content [read $file_open]
> close $file_open
> }
>(3) puts $file_content
> puts "$line test-1 IS A FILE"
> } else {
>
> }
> }
>
> exit
> ---CODE---
>
> When ran - I get the following error at the 'puts $file_content' in
> first if statement. How can I access the 'file_content' from the
> second if statement?

Tcl variables do not exist until you perform a first "set" operation
upon them [1].

In your code, when it first runs, no variables exist (which means
"file_content" also does not exist). The first time line (1) is
executed, the if statement checks the result of a string match. There
are two outcomes from a string match, true and false.

In the instance that the string match returns false the first time
through your code, the if statement causes line (3) to be executed next.

But, remember, first time through, no variables exist until after they
are "set". The "if" just jumped over line (2) without executing it.
So there was never a "set file_content" statement executed anywhere.

Therefore, you get an error from Tcl of trying to access a variable
that does not exist.

Note, you should put curly braces around the conditions in your "if"
statements, i.e.:
if {[string match $file_ext $line]} {
Doing that is faster and safer because without the curly braces there
are instances where you can have code injection security issues.


[1] For pedants, not strictly true, but a close enough approximation
for a beginner.

Jason Guto

unread,
Sep 22, 2017, 4:58:30 PM9/22/17
to
Thinking over what you are telling me and trying hard to understand. Programming is not easy ++laugh++.

I guess what I am finding hard to understand. I am able to get the content from the file_content file into the $file_content variable; however, I cannot access the variable from within the if-statement.

The following code works, and retrieves the context of the '.ameta' file and saves it to the 'file_content' variable, which I can produce with success in the following code.

---code----
set dir "."
set out1 [glob *]

set file_ext "*.ameta"
set sort_out [lsort -dictionary $out1]

foreach line $sort_out {
if [file isfile $line] {
if [string match $file_ext $line] {
set file_open [open $line r]
set file_content [read $file_open]
close $file_open
#global file_content
}
#puts $file_content
puts "$line test-1 IS A FILE"
} else {
}
}
puts $file_content
exit
----code---

Jason Guto

unread,
Sep 22, 2017, 5:00:03 PM9/22/17
to
The idea is... I want to do something with the saved values with the 'file_content' but I need to check first if the '.meta' file exists first, and only if it does exits, perform the next step to only files.

Jason Guto

unread,
Sep 22, 2017, 5:02:11 PM9/22/17
to
On Friday, September 22, 2017 at 4:36:51 PM UTC-4, Rich wrote:
Wow... security issues... thank you for pointing that out.

Thank you for your time and comments Rich... it is much appreciated.

Gerald Lester

unread,
Sep 22, 2017, 5:05:45 PM9/22/17
to
> Thank you again, I am currently working through this code, and trying to understand.
>
> However, let me ask you this - how would I save the content of "file_content" to be able to access from another part of the application? The latter is what I am really trying to do/what I really need.

Once you set it, it continues to exist in that scope.

Your code as posted is running at the global scope, so once file_content
is set, it will continue to exist until your program exits or you
explicitly unset it.

If your code was running inside of a procedure, the variable would
automatically get deleted when the procedure finished executing and
returned to the caller.

To access a global variable inside of a procedure you need to use the
[global] command to tell Tcl you want to access a particular global
(best practices is to put them at the top of the procedure body).

I'll pass on explaining argument passing, upvar and accessing variables
in namespaces -- you need to understand and be comfortable with these
fundamentals before moving on to them.

Jason Guto

unread,
Sep 22, 2017, 5:12:44 PM9/22/17
to
Thank you so much Gerald... I suspect it had to do something with scope/global/private; however, I was not sure.

Still learning - some concepts I am picking up faster then others.

Your help is much appreciated.

Jason Guto

unread,
Sep 22, 2017, 5:35:28 PM9/22/17
to
I believe I am getting closer. It appears TCL works a little different then what I am trying to do. Have been able to get a rough working model to understand... and I am declaring a variable global first called 'set file_content 0' and then changing the variable. However, now i need to do a check if (a) is this a file and (b) is it an ameta file.

maybe something like if [string match $file_ext $line] && 'some other code'.

thank you for the help.

Rich

unread,
Sep 22, 2017, 6:54:41 PM9/22/17
to
Jason Guto <jaso...@gmail.com> wrote:
> Thinking over what you are telling me and trying hard to understand.
> Programming is not easy ++laugh++.

Actually, programming itself is very easy.

Learning programming, that can be hard (esp. if one has no other prior
background to rely upon.

> I guess what I am finding hard to understand. I am able to get the
> content from the file_content file into the $file_content variable;
> however, I cannot access the variable from within the if-statement.

Except your original code was not "access[ing] the variable from within
the if-statement". It was accessing it after the if statement. And if
the body of the if statement never executed, the variable was never
created, which was the cause of your error message.

> The following code works, and retrieves the context of the '.ameta'
> file and saves it to the 'file_content' variable, which I can produce
> with success in the following code.
>
> ---code----
> set dir "."
> set out1 [glob *]
>
> set file_ext "*.ameta"
> set sort_out [lsort -dictionary $out1]
>
> foreach line $sort_out {
> if [file isfile $line] {
> if [string match $file_ext $line] {
> set file_open [open $line r]
> set file_content [read $file_open]
> close $file_open
> #global file_content
> }
> #puts $file_content
> puts "$line test-1 IS A FILE"
> } else {
> }
> }
> puts $file_content
> exit
> ----code---

Your code above works, but only so long as glob * returns at least one
file that is also a match to the pattern "*.ameta". If you move all of
the "*.ameta" files out of the way and try running it, you will get an
error that the "file_content" variable does not exist at the puts
statement at the bottom.

Since you indicate you are a beginner, have you truly grasped the
meaning of what the "if" statement does yet? Because your answers, and
the issue you see, appear to indicate that you've not "got" the meaning
of the "if" statement.

So, if so, lets simplify things:

--- simple code block ---

1: set line "photo.jpg"
2: set file_ext "*.ameta"

3: if {[string match $file_ext $line]} {
4: set found "Yes!"
5: }

6: puts $found
-------------------------

This is a very simplified version of your code. Now, the part to
internalize (and which I suspect you may not yet have done so) is that
an "if" statement makes a choice about whether to run, or *not to run*,
a block of code (that block being the "body" of the "if" (line 4 in the
simple example above)).

So, we start out at line 1. There is no variable named "found" yet
defined. Line 1 defines a variable "line" and gives it the value
"photo.jpg".

Next we run line 2. Again, no variable named "found" exists, and line
2 creates a variable named "file_ext" and gives it a value "*.ameta".

Next, line 3 is run. Line 3 is an "if". So the test part of the "if"
is run (which in this case is the string match command). It compares
the value of the "file_ext" variable (which does exist) and the value
of the "line" variable (which also exists). But because "line"
contains photo.jpg, which does not match to "*.ameta", string match
returns "false" to the "if" statement.

The if statement (line 3) upon receiving a "false" from its test
command, skips over lines 4 and 5. They are never executed [1]. The
next bit of program code to be run then becomes line 6.

Line 6 attempts to retreive the value of a variable named "found". But
there is no variable named "found" in existance yet, because the
command that would have created a variable named "found" (line 4) was
skipped over by the if statement receiving false.

This tiny bit of code illustrates exactly how and why you are receiving
the error message about your variable not existing. The only command
you have in your entire bit of code that would create the variable is
inside the body of an "if". In the case that the "if" always receives
"false" from its test command, then the command that would actually
create the variable is never executed, and the variable is never
created. Therefore you get the error message about variable does not
exist.








[1] Note for the pedantic, yes, line 5 isn't executed. But for the
explanation the statement holds, it is "skipped over" in one sense.

Rich

unread,
Sep 22, 2017, 6:59:10 PM9/22/17
to
Well, your description above is somewhat confusing to me.

Your description could mean:

1) you want to do something with the content of some file, but only
when another file named *.ameta also exists.
or
2) you want to do something with the content of files named *.ameta
when those files exist
or
3) ??? There might be a third interpretation, but I can't think of
one right now.

lmn...@gmail.com

unread,
Oct 15, 2017, 10:52:45 PM10/15/17
to
Make sure you understand this result and play around with this example for your specific case, I am certain it will lead you to nirvana:

set x {hello world!}

puts x=\[$x\]

if {0} {
set x {Harry!}
}

puts x=\[$x\]

if {1} {
set x {Sally!}
}

puts x=\[$x\]


Result:
x=[Hello World!]
x=[Hello World!]
x=[Sally!]



0 new messages