Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Variable incrementing in bash

Consider the following script:

#!/bin/bash

num=0
cat file | while read line; do
    echo "$line"
    lines[$num]="$line"
    ((num++))
    echo "num = $num"
done

echo "end num = $num"

i=0
while [ $i -lt $num ]; do
    echo "${lines[$i]}"
    ((i++))
done

Normally, it should read the file line by line, store the result in an array, then go through the array and print it line by line. The problem is that the variable $num resets somehow after the first loop exits. The output of this script for me is the following (using a file with some random garbage in it):

dsfkljhhsdfsdfshdjkfgd
num = 1
fdfgdfgdfg
num = 2
dfgdfgdfgdfg
num = 3
dfgdfgdfgdfgdfg
num = 4
dfgdfgdfgdfgdfgd
num = 5
fgdfgdfgdfg
num = 6
dfgdfgdfgdfg
num = 7
dfgdfgdfgdfgdfg
num = 8
dfgdfgdfgdfg
num = 9
dfgdfgdgdgdg
num = 10
dfgdffgdgdgdg
num = 11
end num = 0

Why is this? How do I achieve to remember the variable? I am using bash 3.1.17 on SUSE Linux 10.

like image 739
petersohn Avatar asked Sep 20 '11 08:09

petersohn


People also ask

Can I use ++ in bash?

Similar to other programming language bash also supports increment and decrement operators. The increment operator ++ increases the value of a variable by one. Similarly, the decrement operator -- decreases the value of a variable by one.

Can you do += in bash?

Bash is a widely used shell in Linux, and it supports the '+=' operator to concatenate two variables. As the example above shows, in Bash, we can easily use the += operator to concatenate string variables. Bash's += works pretty similar to compound operators in other programming languages, such as Java.

How do you increment to a variable?

There are two ways to use the increment operator; prefix and postfix increment. The prefix increment looks like ++variablename; while the postfix increment looks like variablename++; . Both of these operations add one to the value in the variable.

What is $@ in bash?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc.


1 Answers

Why? It's because this:

cat file | while read line; do
    echo "$line"
    lines[$num]="$line"
    ((num++))
    echo "num = $num"
done

runs the while statement in a separate process, with its own environment, not touching the parent environment. You'll find, similarly, that the lines array is not there either.

The following simplified script shows this in action:

#!/bin/bash
export xyzzy=42
echo urk | while read line; do
    xyzzy=999
    echo $xyzzy
done
echo $xyzzy

The output of that script is:

999
42

because the setting of the variable to 999 is done in the subprocess.

Bottom line, if you want information to be reflected in the current process (the script), you'll need to do the work in the script or find some other way to get the information out of the sub-process.

If you use input redirection rather than starting a sub-process pipeline, it should work as you want. That's because the while bit is then done in the context of the current process rather than a separate process in a pipeline. For example:

#!/bin/bash
export xyzzy=42
while read line; do
    xyzzy=999
    echo $xyzzy
done <<EOF
hello
EOF
echo $xyzzy

will produce:

999
999

For your specific case, replace:

done <<EOF
hello
EOF

with:

done <file
like image 71
paxdiablo Avatar answered Oct 22 '22 09:10

paxdiablo