Loop control from within a subshell
Asked Answered
I

2

6

I want to use subshells for making sure environment changes do not affect different iterations in a loop, but I'm not sure I can use loop control statements (break, continue) inside the subshell:

#!/bin/sh
export A=0
for i in 1 2 3; do
  (
  export A=$i
  if [ $i -eq 2 ]; then continue ; fi
  echo $i
  )
done
echo $A

The value of A outside the loop is unaffected by whatever happens inside, and that's OK. But is it allowed to use the continue inside the subshell or should I move it outside? For the record, it works as it is written, but maybe that's an unreliable side effect.

Inspan answered 29/1, 2014 at 12:37 Comment(2)
That's interesting. Since subshells are separate processes (have their own $BASHPID) one would expect your code to throw the usual error: continue: only meaningful in a 'for', 'while', or 'until' loopArchuleta
Unless your real subshell does something a bit more involved in reality, the export in the subshell is completely pointless.Tedesco
C
3

Just add

echo "out $i"

after the closing parenthesis to see it does not work - it exits the subshell, but continues the loop.

The following works, though:

#! /bin/bash
export A=0
for i in 1 2 3; do
    (
        export A=$i
        if [ $i -eq 2 ]; then exit 1 ; fi
        echo $i
    ) && echo $i out      # Only if the condition was not true.
done
echo $A
Cleasta answered 29/1, 2014 at 12:54 Comment(4)
But it doesn't explain why bash doesn't throw an error? Try this and you will get an error: (if [ 1 != 2 ]; then continue; fi). Why doesn't the same thing happen for OP when subshell is spawned in a loop?Archuleta
This explanation helped me understand: lists.gnu.org/archive/html/help-bash/2012-10/msg00023.htmlArchuleta
@Archuleta So, if I understand it correctly, break and continue inside a loop-contained subshell simply cause an exit from the subshell, but do not affect the loop. If there is nothing after the subshell in the loop (as in my example), the effect is equivalent to continue.Inspan
@Inspan - Yes, and the reason it's not generating an error is because the subshell is spawned in a surrounding loop context.Archuleta
E
0

Can you simply wrap the entire loop in a subshell?

#!/bin/sh
export A;
A=0
(
    for i in 1 2 3; do
        A=$i
        if [ $i -eq 2 ]; then continue ; fi
        echo $i
    done
)
echo $A

Note also that you don't need to use export every time you assign to the variable. export does not export a value; it marks the variable to be exported, so that any time a new process is created, the current value of that variable will be added to the environment of the new process.

Elliot answered 29/1, 2014 at 14:30 Comment(1)
Not in my real case, I also need one iteration not to affect the next. And I don't know in advance which variables will be exported, that depends on the contents of an iteration-specific file.Inspan

© 2022 - 2024 — McMap. All rights reserved.