Skip to main content
nitpick: it should display a leading space here, the one between $a and "is"
Source Link
ilkkachu
  • 147.9k
  • 16
  • 268
  • 441

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done once ALL of them are finished.

My problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons:

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The behavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.

Unsetting a beforehand makes the second script return this

 is 1
 is 2
 is 3

i.e. the variable is never set and was dragged from my previous run.

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done once ALL of them are finished.

My problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons:

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The behavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.

Unsetting a beforehand makes the second script return this

is 1
is 2
is 3

i.e. the variable is never set and was dragged from my previous run.

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done once ALL of them are finished.

My problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons:

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The behavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.

Unsetting a beforehand makes the second script return this

 is 1
 is 2
 is 3

i.e. the variable is never set and was dragged from my previous run.

deleted 39 characters in body; edited title
Source Link
Jeff Schaller
  • 68.8k
  • 35
  • 122
  • 264

Undestanding Understanding backgrounded variable assignments and the wait command

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done, once ALL of them are finished.

Now myMy problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons:

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The bahaviorbehavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.


EDIT following comment:

Unsetting a beforehand makes the second script return this

is 1
is 2
is 3

Ii.e. the variable is never set and was dragged from my previous run.

Undestanding the wait command

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done, once ALL of them are finished.

Now my problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The bahavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.


EDIT following comment:

Unsetting a beforehand makes the second script return this

is 1
is 2
is 3

I.e. the variable is never set and was dragged from my previous run.

Understanding backgrounded variable assignments and the wait command

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done once ALL of them are finished.

My problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons:

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The behavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.

Unsetting a beforehand makes the second script return this

is 1
is 2
is 3

i.e. the variable is never set and was dragged from my previous run.

added 236 characters in body
Source Link
FelixJN
  • 14.1k
  • 2
  • 36
  • 55

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done, once ALL of them are finished.

Now my problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The bahavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.


EDIT following comment:

Unsetting a beforehand makes the second script return this

is 1
is 2
is 3

I.e. the variable is never set and was dragged from my previous run.

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done, once ALL of them are finished.

Now my problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The bahavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.

In man bash it says:

wait [-fn] [id ...]

Wait for each specified child process and return its termination status. Each id may be a process ID or a job specification; if a job spec is given, all processes in that job's pipeline are waited for. If id is not given, all currently active child processes are waited for, and the return status is zero. If the -n option is supplied, wait waits for any job to terminate and returns its exit status.

And typical examples like

 command1 & command2 & command3 & wait

will mean the three commands run in parallel and the next step is only done, once ALL of them are finished.

Now my problem lies in the results of these two bash scripts:

#!/bin/bash
for i in 1 2 3 ; do
  a=$i
  echo "$a is $i"
done 2>/dev/null

Result:

1 is 1
2 is 2
3 is 3

Pretty much what I expected. Now I assume assigning the variable is a long process, so I wait for it:

#!/bin/bash
  for i in 1 2 3 ; do
  a=$i & wait
  echo "$a is $i"
done 2>/dev/null

Result is:

3 is 1
3 is 2
3 is 3

and I am quite baffled for the following reasons

  1. The only process wait should be waiting to finish is assigning the variable, then the next step in the script should be run (echo). a=3 should only happen in the last iteration of the loop.
  2. As far as I know, for-loops are run in subshells and wait has a scope only for the shell it was launched in. So it should not even be waiting for the for-loop to finish (as this is the parent).
  3. At no point have I specified the echo to run in parallel to some other process, so I did not expect a racing condition.

So why is the a-variable set with the last loop iteration when the variable $i is not? What part of the wait command did I misunderstand? The bahavior is completely off my expectations.

GNU bash, version 5.0.3(1) on a 5.7.0-0.bpo.2-amd64 Linux kernel.


EDIT following comment:

Unsetting a beforehand makes the second script return this

is 1
is 2
is 3

I.e. the variable is never set and was dragged from my previous run.

Source Link
FelixJN
  • 14.1k
  • 2
  • 36
  • 55
Loading