0

How can I use the stdout of the echo command as an argument in a for loop.

echo NUMBER | for i in {1..$NUMBER}; do if [ $(( $i % 2 )) -eq 0 ]; then echo "even"; fi; done

In this example, I wish to loop over a sequence of numbers with a length equal to the integer outputted by echo. How can I do this in a single command line?

Acheros
  • 3
  • 2

2 Answers2

2

The list for a for loop cannot read from standard input. However, you can't combine brace expansion and parameter expansion like this in the first place (a common mistake).

Use a C-style for loop instead, setting the value of NUMBER however you like prior to the loop.

read NUMBER  # reads from standard input
for ((i=1; i <= $NUMBER; i++)); do
    ...
done

This also lets you skip the repeated division in your original question. Instead of filtering the even numbers from the full range, just generate only the even numbers.

for ((i=2; i <= $NUMBER; i+= 2)); do
    echo even
done
chepner
  • 497,756
  • 71
  • 530
  • 681
  • This works, but I would like it to fit on a single line (executable from command line). – Acheros Oct 02 '22 at 13:53
  • Write `read NUMBER; for ((...); do ...; done` if you like. The newlines aren't particularly significant. Semicolons serve the same purpose. – chepner Oct 02 '22 at 14:35
0

As mentioned by @chepner, the for loop alone can't accomplish what you're trying to do. One work around is to use the read builtin to save/capture the input and the {} braces for command grouping. Something like.

echo 10 | { read -r input; for ((i=1; i<=input; i++)); do ((i%2==0)) && printf '%d is even\n' "$i"; done;  }

You could also do things like:

{ read -r input; for ((i=1; i<=input; i++)); do ((i%2==0)) && printf '%d is even\n' "$i"; done; } < <(echo 10)

and:

{ read -r input; for ((i=1; i<=input; i++)); do ((i%2==0)) && printf '%d is even\n' "$i"; done;  } <<< 10

Output

2 is even
4 is even
6 is even
8 is even
10 is even
Jetchisel
  • 7,493
  • 2
  • 19
  • 18