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.

Jellby
  • 2,360
  • 3
  • 27
  • 56
  • 1
    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' loop` – grebneke Jan 29 '14 at 12:54
  • Unless your real subshell does something a bit more involved in reality, the `export` in the subshell is completely pointless. – tripleee Jan 29 '14 at 14:51

2 Answers2

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
choroba
  • 231,213
  • 25
  • 204
  • 289
  • 1
    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? – grebneke Jan 29 '14 at 12:57
  • 1
    This explanation helped me understand: http://lists.gnu.org/archive/html/help-bash/2012-10/msg00023.html – grebneke Jan 29 '14 at 12:59
  • @grebneke 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`. – Jellby Jan 29 '14 at 13:09
  • @Jellby - Yes, and the reason it's not generating an error is because the subshell is spawned in a surrounding loop context. – grebneke Jan 29 '14 at 13:15
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.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • 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. – Jellby Jan 29 '14 at 14:42