The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex
for i in `seq 1 $END`; do echo $i; done
ReplyDeletediscussion
ReplyDeleteUsing seq is fine, as Jim Robert suggested. Pax Diablo suggested a bash loop to avoid calling a subprocess, with the additional advantage of being more memory friendly if $END is too large. Zathrus spotted a typical bug in the loop implementation, and also hinted that since i is a text variable, continuous conversions to-and-fro numbers are performed with an associated slow-down.
integer arithmetic
This is an improved version of the bash loop:
typeset -i i END
let END=5 i=1
while ((i<=END)); do
echo $i
…
let i++
done
If the only thing that we want is the echo, then we could write echo $((i++)).
ephemient taught me something: bash allows for ((expr;expr;expr)) constructs. Since I've never read the whole man page for bash (like I've done with the ksh man page, and that was a long time ago), I missed that.
So,
typeset -i i END # let's be explicit
for ((i=1;i<=END;++i)); do echo $i; done
seems to be the cleanest way, and possibly the "fastest"; it sure won't be necessary to allocate memory to consume seq's output, which could be a problem if END is very large.
the initial question
eschercycle noted that the {a..b} bash notation works only with literals; true, accordingly to the bash manual. One can overcome this obstacle with a single (internal) fork() without an exec() (as is the case with calling seq, which being another image requires a fork+exec):
for i in $(eval echo "{1..$END}"); do
Both eval and echo are bash builtins, but a fork() is required for the command substitution (the $(…) construct).
The seq method is the simplest, but Bash has built-in arithmetic evaluation.
ReplyDeleteEND=5
for ((i=1;i<=END;i++)); do
echo $i
done
# ==> outputs 1 2 3 4 5 on separate lines
The "for ((expr1;expr2;expr2))" construct works just like "for (expr1;expr2;expr3)" in C and similar languages, and like other ((expr)) cases, Bash treats them as arithmetic.
You can use
ReplyDeletefor i in $(seq $END); do echo $i; done
If you're on BSD / OS X you can use jot instead of seq:
ReplyDeletefor i in $(jot $END); do echo $i; done
This works for me in bash:
ReplyDeleteEND=5
i=1 ; while [[ $i -le $END ]] ; do
echo $i
((i = i + 1))
done
Since the "how to" part of the question has been completely answered by now, I will comment on why the original expression didn't work.
ReplyDeleteFrom man bash:
Brace expansion is performed before
any other expansions, and any
characters special to other
expansions are preserved in the
result. It is strictly textual. Bash
does not apply any syntactic
interpretation to the context of
the expansion or the text between the
braces.
So, brace expansion is something done early as a purely textual macro operation, before parameter expansion.
Shells are highly optimized hybrids between macro processors and more formal programming languages. In order to optimize the typical use cases, the language is made rather more complex and some limitations are accepted.
Another layer of indirection:
ReplyDeletefor i in $(eval echo {1..$END}); do
∶
My version of bash doesn't seem to support the curly brace notation at all.
ReplyDeleteCan you do this?
for i in `echo {1..$END}`; do echo $i; done
Update: I found a bash that supports the curly braces; the above does not work.
These are all nice but seq is supposedly deprecated and most only work with numeric ranges.
ReplyDeleteIf you enclose your for loop in double quotes, the start and end variables will be dereferenced when you echo the string, and you can ship the string right back to BASH for execution. $i needs to be escaped with \'s so it is NOT evaluated before being sent to the subshell.
RANGE_START=a
RANGE_END=z
echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash
This output can also be assigned to a variable:
VAR=`echo -e "for i in {$RANGE_START..$RANGE_END}; do echo \\${i}; done" | bash`
The only "overhead" this should generate should be the second instance of bash so it should be suitable for intensive operations.
You would still use seq in cases where you needed to generate sequences of real numbers. The
ReplyDeleteBash for loop only supports integers.