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
    For you my all loved XY friends, a big file with CRLFs only is what I am actually trying to get. – 41754 Aug 27 '14 at 12:28
  • Testing nl with lines alot, tabs and XY pow are what I got. – 41754 Aug 27 '14 at 12:48
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.

| improve this answer | |
  • 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 '14 at 12:35
  • 3
    @mikeserv, yes Pourquoi faire simple quand on peut faire compliqué ? like they say in France. – Stéphane Chazelas Aug 27 '14 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 '14 at 12:39
  • Telling you to work a pearl for it. – 41754 Aug 27 '14 at 12:41
2

@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.

| improve this answer | |

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.