fix scope problem with variable in bash script
Obviously I've reduced and rewitten it to better point out the problem in this script. The question is, how should the variable "count" be declared so that it isn't treated as two, completely different variables (with exactly the same name)? If you want to try to run it, it takes a filename as an commandline argument. ======================== #!/bin/bash #How to declare the variable "count"??? count=0 cat $1 | while read line do count=$((count+1)) echo -n "$count " done echo echo File $1 has $count lines. ======================== Thanks.
On 26.07.2022 15:25, kf wrote:
Obviously I've reduced and rewitten it to better point out the problem in this script. The question is, how should the variable "count" be declared so that it isn't treated as two, completely different variables (with exactly the same name)?
It has nothing to do with declaration or scope.
If you want to try to run it, it takes a filename as an commandline argument.
======================== #!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
Right hand of pipe is executed in separate process (subshell), so any changes done there do not affect main shell process. You can redirect from file instead while read ... ... done < $1
echo echo File $1 has $count lines.
========================
Thanks.
On 7/26/22 8:41 AM, Andrei Borzenkov wrote:
On 26.07.2022 15:25, kf wrote:
Obviously I've reduced and rewitten it to better point out the problem in this script. The question is, how should the variable "count" be declared so that it isn't treated as two, completely different variables (with exactly the same name)?
It has nothing to do with declaration or scope.
If you want to try to run it, it takes a filename as an commandline argument.
======================== #!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
Right hand of pipe is executed in separate process (subshell), so any changes done there do not affect main shell process.
Yes, I was aware that another process started with "while...". But is there no way to specify a variable type which can access that other process? There can be merit in isolating variables, even when they have the same name, but as my case here shows, there are also times when a variable's value should be accessible throughout the body of code, e.g., when in C a global or static variable is used. Is that simply impossible in bash?
You can redirect from file instead
while read ... ... done < $1
echo echo File $1 has $count lines.
========================
That's a good suggestion. Thanks.
Thanks.
On 7/26/22 11:48, kf wrote:
Yes, I was aware that another process started with "while...". But is there no way to specify a variable type which can access that other process? There can be merit in isolating variables, even when they have the same name, but as my case here shows, there are also times when a variable's value should be accessible throughout the body of code, e.g., when in C a global or static variable is used. Is that simply impossible in bash?
No, bash variables are untyped. You can hint to the interpreter that you want to consider a variable of type int, e.g. declare -i myint Or array, declare -a myarray Or associative array declare -A array Or a nameref (similar to old indirect access) declare -n mytyperef But those are just hints, nothing prevents myint="mystring". It's up to you to know what is held by each variable. There are ways to test if what is held is an int, etc.. but those are also things you implement. -- David C. Rankin, J.D.,P.E.
On 29.07.2022 06:27, David C. Rankin wrote:
But those are just hints, nothing prevents myint="mystring".
bor@bor-Latitude-E5450:~$ a="1+2" bor@bor-Latitude-E5450:~$ echo $a 1+2 bor@bor-Latitude-E5450:~$ declare -i b bor@bor-Latitude-E5450:~$ b="1+2" bor@bor-Latitude-E5450:~$ echo $b 3 bor@bor-Latitude-E5450:~$
On 7/28/22 23:44, Andrei Borzenkov wrote:
On 29.07.2022 06:27, David C. Rankin wrote:
But those are just hints, nothing prevents myint="mystring".
bor@bor-Latitude-E5450:~$ a="1+2" bor@bor-Latitude-E5450:~$ echo $a 1+2 bor@bor-Latitude-E5450:~$ declare -i b bor@bor-Latitude-E5450:~$ b="1+2" bor@bor-Latitude-E5450:~$ echo $b 3 bor@bor-Latitude-E5450:~$
Chuckling -- good example, but with b="mystring", echo $b would still by "mystring" ;-) -- David C. Rankin, J.D.,P.E.
On 7/28/22 23:56, David C. Rankin wrote:
Chuckling -- good example,
but with b="mystring", echo $b would still by "mystring" ;-)
Though with Arithmetic Expansion after declare -i it would evaluate 0. The point I was making is there is no error of any type associate with b="mystring" after declare -i b. -- David C. Rankin, J.D.,P.E.
On 26/07/2022 14:25, kf wrote:
Obviously I've reduced and rewitten it to better point out the problem in this script. The question is, how should the variable "count" be declared so that it isn't treated as two, completely different variables (with exactly the same name)?
If you want to try to run it, it takes a filename as an commandline argument.
======================== #!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines.
========================
Thanks.
The pipe character ('|') at line 6 creates a subshell => the result of the increment is not passed on the the father. Use input re-direction instead, and it works: ---------------------<cut>----------------------- #!/bin/bash #How to declare the variable "count"??? count=0 while read line; do count=$(( $count + 1 )) echo -n "$count " done < $1 echo echo File $1 has $count lines. ---------------------<cut>----------------------- This being said, 'wc -l' would do the trick, e.g.: ---------------------<cut>----------------------- count=$(wc -l $1 | cut -d ' ' -f 1) ---------------------<cut>----------------------- (unless the point was not about counting lines, of course) HTH Ph. A. -- *Philippe Andersson* Unix System Administrator IBA Particle Therapy | Tel: +32-10-475.983 Fax: +32-10-487.707 eMail: pan@iba-group.com <http://www.iba-worldwide.com> Disclaimer | Use of IBA e-communication<https://iba-worldwide.com/disclaimer> The contents of this e-mail message and any attachments are intended solely for the recipient (s) named above. This communication is intended to be and to remain confidential and may be protected by intellectual property rights. Any use of the information contained herein (including but not limited to, total or partial reproduction, communication or distribution of any form) by persons other than the designated recipient(s) is prohibited. Please notify the sender immediately by e-mail if you have received this e-mail by mistake and delete this e-mail from your system. E-mail transmission cannot be guaranteed to be secure or error-free. Ion Beam Applications does not accept liability for any such errors. Thank you for your cooperation.
On 7/26/22 8:59 AM, Philippe Andersson wrote:
On 26/07/2022 14:25, kf wrote:
Obviously I've reduced and rewitten it to better point out the problem in this script. The question is, how should the variable "count" be declared so that it isn't treated as two, completely different variables (with exactly the same name)?
If you want to try to run it, it takes a filename as an commandline argument.
======================== #!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines.
========================
Thanks.
The pipe character ('|') at line 6 creates a subshell => the result of the increment is not passed on the the father.
Use input re-direction instead, and it works:
---------------------<cut>----------------------- #!/bin/bash
#How to declare the variable "count"??? count=0
while read line; do count=$(( $count + 1 )) echo -n "$count " done < $1
echo echo File $1 has $count lines. ---------------------<cut>-----------------------
Good suggestion. Thanks for that.
This being said, 'wc -l' would do the trick, e.g.:
---------------------<cut>----------------------- count=$(wc -l $1 | cut -d ' ' -f 1) ---------------------<cut>-----------------------
(unless the point was not about counting lines, of course)
:>) Yeah, there was no sense in my quoting the entire script, so I edited it way down to little more than a school lesson. Among other things, the full script detected and counted different kinds of lines separately, what 'wc' could not do.
HTH
Ph. A.
--
*Philippe Andersson* Unix System Administrator IBA Particle Therapy | Tel: +32-10-475.983 Fax: +32-10-487.707 eMail: pan@iba-group.com <http://www.iba-worldwide.com>
Disclaimer | Use of IBA e-communication<https://iba-worldwide.com/disclaimer>
The contents of this e-mail message and any attachments are intended solely for the recipient (s) named above. This communication is intended to be and to remain confidential and may be protected by intellectual property rights. Any use of the information contained herein (including but not limited to, total or partial reproduction, communication or distribution of any form) by persons other than the designated recipient(s) is prohibited. Please notify the sender immediately by e-mail if you have received this e-mail by mistake and delete this e-mail from your system. E-mail transmission cannot be guaranteed to be secure or error-free. Ion Beam Applications does not accept liability for any such errors. Thank you for your cooperation.
On Wednesday 27 July 2022, kf wrote:
#!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines.
As other have explained, the pipe receiver runs in it's own subprocess. If you were in a situation where you did really have to read from a pipe, you could also code it as follows: #!/bin/bash cat $1 | { count=0 while read line do count=$((count+1)) echo -n "$count " done echo echo File $1 has $count lines. }
On 7/26/22 5:56 PM, Michael Hamilton wrote:
On Wednesday 27 July 2022, kf wrote:
#!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines.
As other have explained, the pipe receiver runs in it's own subprocess. If you were in a situation where you did really have to read from a pipe, you could also code it as follows:
#!/bin/bash cat $1 | { count=0 while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines. }
Nice. Thanks. It's always good to have options.
FYI, both of these are UUOC. while read line do # foo here done < $1 Best, Georg On 7/27/22 19:35, kf wrote:
On 7/26/22 5:56 PM, Michael Hamilton wrote:
On Wednesday 27 July 2022, kf wrote:
#!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines.
As other have explained, the pipe receiver runs in it's own subprocess. If you were in a situation where you did really have to read from a pipe, you could also code it as follows:
#!/bin/bash cat $1 | { count=0 while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines. }
Nice. Thanks. It's always good to have options.
Lots of good answers on this list. Thanks again to all. Have to say, if efficient code were the sole concern, we'd get there better with a compiled language. On 7/27/22 1:56 PM, Georg Pfuetzenreuter wrote:
FYI, both of these are UUOC.
while read line do # foo here done < $1
Best, Georg
On 7/27/22 19:35, kf wrote:
On 7/26/22 5:56 PM, Michael Hamilton wrote:
On Wednesday 27 July 2022, kf wrote:
#!/bin/bash
#How to declare the variable "count"??? count=0
cat $1 | while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines.
As other have explained, the pipe receiver runs in it's own subprocess. If you were in a situation where you did really have to read from a pipe, you could also code it as follows:
#!/bin/bash cat $1 | { count=0 while read line do count=$((count+1)) echo -n "$count " done
echo echo File $1 has $count lines. }
Nice. Thanks. It's always good to have options.
participants (6)
-
Andrei Borzenkov
-
David C. Rankin
-
Georg Pfuetzenreuter
-
kf
-
Michael Hamilton
-
Philippe Andersson