74

I have a simple BASH command that looks like

for i in `seq 2`; do echo $i; done; > out.dat

When this runs the output of seq 2 is output to the terminal and nothing is output to the data file (out.dat)

I am expecting standard out to be redirected to out.dat like it does simply running the command seq 2 > out.dat

3 Answers 3

106

Remove your semicolon.

for i in `seq 2`; do echo "$i"; done > out.dat

SUGGESTIONS

Also as suggested by Fredrik Pihl, try not to use external binaries when they are not needed, or at least when practically not:

for i in {1..2}; do echo "$i"; done > out.dat
for (( i = 1; i <= 2; ++i )); do echo "$i"; done > out.dat
for i in 1 2; do echo "$i"; done > out.dat

Also, be careful of outputs in words that may cause pathname expansion.

for a in $(echo '*'); do echo "$a"; done

Would show your files instead of just a literal *.

$() is also recommended as a clearer syntax for command substitution in Bash and POSIX shells than backticks (`), and it supports nesting.

The cleaner solutions as well for reading output to variables are

while read var; do
    ...   
done < <(do something)

And

read ... < <(do something)  ## Could be done on a loop or with readarray.

for a in "${array[@]}"; do
    :
done

Using printf can also be an easier alternative with respect to the intended function:

printf '%s\n' {1..2} > out.dat
Sign up to request clarification or add additional context in comments.

6 Comments

Why seq instead of for i in {1..2}; do ...?
@FredrikPihl Yes it's better. Or (( i = 1 ; i <= 2; ++i )), or simply in 1 2 for compatibility. My answer is only about the problem with redirection, although I tried to fix one: "$i".
I just thought you could update your answer with an alternative better way to solve the problem without resorting to using external binaries :-)
@FredrikPihl Well it's not really connected to the problem and is more of a suggestion instead, but I made an update anyway.
This example led me to realize that I can pipe the done statement to other things like sort, for example for i in foo bar baz; do echo $i | base64; done | sort | base64 -d
|
9

Another possibility, for the sake of completeness: You can move the output inside the loop, using >> to append to the file, if it exists.

for i in `seq 2`; do echo $i >> out.dat; done;

Which one is better certainly depends on the use case. Writing the file in one go is certainly better than appending to it a thousand times. Also, if the loop contains multiple echo statements, all of which shall go to the file, doing done > out.dat is probably more readable and easier to maintain. The advantage of this solution, of course, is that it gives more flexibility.

2 Comments

Doing a single redirect outside the loop is definitely better for performance.
if you conditionally want to put to a file, it is handy to put, outputting, in the loop
6

Try:

(for i in `seq 2`; do echo $i; done;) > out.dat

7 Comments

It's not necessary to place it on a subshell. The semicolon just have to be removed to make the redirection part of the block.
True, just removing the semicolon will do in this case. Subshell, ( ), can be used to collect output from larger number of commands, say multiple for-loops.
Unable to find a good subshell article on stackoverflow. Here is one external: tldp.org/LDP/abs/html/subshells.html
@svante I agree with enclosing it around for more commands, but you could also do that with {} when it's not necessary to create another process for the subshell and keeping the variable changes from the higher block. A situation only when it can't be helped is when you place them on a pipeline since they are placed on a subshell by default, where not laspipe is set and commands are on the end, although using process substitutions are the way to go for it.
The for loop is already a compound command that groups its body; the subshell here is pointless.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.