Problem 1を前回のように包除原理で解くのはプログラミングの問題としてはやや邪道です。ループを回す方法を考えてみましょう。
while/untilを使うことも使うことも可能ですが、やはりforを使うほうがフローが分かりやすいでしょう。
forには2種類あります。一つは次のような方法です。
#!/bin/bash N=$1 for n in `seq 1 $((N-1))`; do echo $n done
seqは等差数列を出力するコマンドです。引数が1つなら1から第2引数まで、引数が2つなら第1引数から第2引数までstep=1で、引数が3つなら第2引数がstepです(Pythonのrangeと順番が違うので注意)。
コマンドを`で括るとその標準出力がnに次々に代入されます。デフォルトではwhite spaceで区切られて代入されます。
``の代わりに$()で括る方法もありますが、``のほうが親しみがある人が多いのではないかと思います。
これと同様に、次のような方法もあります。
for n in {1..10}; do echo $n done
しかし、この方法は変数が使えないので、使い道はあまりないでしょう。
もう一つはCのような使い方です。
for((n=1; n < N; ++n)); do echo $n done
前回と同様、二重括弧で括るとCと同様の表記が使えます。また、seqは全ての値が生成されてからforが回りだすので、途中でbreakするときは効率が悪くなる恐れがあります。そうでないときは、seqのほうが速いようです。
ついでですが、forの行は、
for((n=1; n < N; ++n)) do
とも書けます。;が改行の代わりに使えるため、行数削減で上のように書いています。