5

IINM my system is failing when bashing

for i in {0..10000000}; #   Seven zeroes.
do
    false;
done #   `bash` exited and its `tmux` pane/window was closed.

or

for i in $(seq 0 10000000); #   Seven zeroes.
do
    false;
done #   `bash` exited and its `tmux` pane/window was closed.

but not when

for i in {0..1000000}; #   Six zeroes.
do
    false;
done #   Finished correctly.

Can you please briefly explain the internals of this behavior and prompt a workaround for getting the task done?

2
  • 2
    For you my all loved XY friends, a big file with CRLFs only is what I am actually trying to get.
    – 41754
    Aug 27, 2014 at 12:28
  • Testing nl with lines alot, tabs and XY pow are what I got.
    – 41754
    Aug 27, 2014 at 12:48

2 Answers 2

11
+50

for i in {0..1000000} and for i in $(seq 1000000) both build up a big list and then loop over it. That's inefficient and uses a lot of memory.

Use:

for ((i = 0; i<= 1000000; i++))

instead. Or POSIXly:

i=0; while [ "$i" -le 1000000 ]; do
  ...
  i=$(($i + 1))
done

Or:

seq 1000000 | xargs...

To get a file full of CRLFs:

yes $'\r' | head -n 1000000 >  file

Generally, loops should be avoided when possible in shells.

4
  • 1
    there's also the old /dev/zero/ thing... like tr \\0 \\r </dev/zero | tee - - - | dd or head or whatever... It might be better to mount a tmpfs of that size and fill it then cp to a file. Maybe not...
    – mikeserv
    Aug 27, 2014 at 12:35
  • 3
    @mikeserv, yes Pourquoi faire simple quand on peut faire compliqué ? like they say in France. Aug 27, 2014 at 12:38
  • dang man. you really are a funny guy sometimes. now I have to translate that... ahh. the double entendre. that's probably French too. and, yeah, I dunno why I do. but I do.
    – mikeserv
    Aug 27, 2014 at 12:39
  • Telling you to work a pearl for it.
    – 41754
    Aug 27, 2014 at 12:41
1

@Stéphane Chazelas gave a great answer up there.

Mine is not an answer. I just it got curious about the efficiency of the different solutions, so I thought I should share my results...

~# i=0 ; time while [ "$i" -le 1000000 ]; do ((i++)) ;done
real    0m21.753s

~# time for ((i = 0; i<= 1000000; i++))  ;do : ;done
real    0m15.791s

~# time for i in {0..1000000} ;do : ;done
real    0m8.897s

~# time for i in $(seq 0 1000000) ;do : ;done
real    0m7.760s

:~# time seq 1000000 | xargs true
real    0m0.938s

~# time yes $'\r' | head -n 1000000 >/dev/null
real    0m0.048s

The yes answer is the clear winner. :-) Besides, it actually does the work that the OP needed.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.