Bashで「1時間以内に解けなければプログラマ失格となってしまう5つの問題が話題に」の5問目を解いてみた

$ cat p5.sh 
#!/bin/bash.exe

calc(){
    if [ $1 -eq 10 ]; then
        [ $(expr $2) -eq 100 ] && echo ${2// /}
    else
        for x in ' + ' ' - ' ''; do
            calc $(expr $1 + 1) "${2}${x}${1}"
        done
    fi
}

calc 2 "1"
  
$ time bash p5.sh 
1+2+3-4+5+6+78+9
1+2+34-5+67-8+9
1+23-4+5+6+78-9
1+23-4+56+7+8+9
12+3+4+5-6-7+89
12+3-4+5+67+8+9
12-3-4+5-6+7+89
123+4-5+67-89
123+45-67+8-9
123-4-5-6-7+8-9
123-45-67+89

real    0m39.032s
user    0m16.773s
sys     0m20.385s

  • exprは半角スペースが必要である
  • 変数はlocal指定しないとグローバル変数になるため、再帰呼び出しで変数が上書きされる
  • 引数($1,$2...)はローカル変数
$ cat test.sh 
func(){
    v=$1
    gv=$1
    local lv=$1
    if [ ${#1} -lt 5 ]; then
        echo "Before:"
        echo "  Argument         $1"
        echo "  Global(inside)   $v"
        echo "  Global(outside)  $gv"
        echo "  Local            $lv"
        aaa "$1+"
        echo "After:"
        echo "  Argument         $1"
        echo "  Global(inside)   $v"
        echo "  Global(outside)  $gv"
        echo "  Local            $lv"
    fi
}
gv=""
func "a"
$ bash test.sh 
Before:
  Argument         a
  Global(inside)   a
  Global(outside)  a
  Local            a
Before:
  Argument         a+
  Global(inside)   a+
  Global(outside)  a+
  Local            a+
Before:
  Argument         a++
  Global(inside)   a++
  Global(outside)  a++
  Local            a++
Before:
  Argument         a+++
  Global(inside)   a+++
  Global(outside)  a+++
  Local            a+++
After:
  Argument         a+++
  Global(inside)   a++++
  Global(outside)  a++++
  Local            a+++
After:
  Argument         a++
  Global(inside)   a++++
  Global(outside)  a++++
  Local            a++
After:
  Argument         a+
  Global(inside)   a++++
  Global(outside)  a++++
  Local            a+
After:
  Argument         a
  Global(inside)   a++++
  Global(outside)  a++++
  Local            a
  • 連続したブレース展開では変数が使えないのでseqを使う
$ echo {1..10}
1 2 3 4 5 6 7 8 9 10
$ a=1
$ echo $a
1
$ echo {${a}..10}
{1..10}
$ echo {"${a}"..10}
{1..10}
$ for n in {1..5}; do echo -n $n; done; echo ""
12345
$ for n in `seq $a 5`; do echo -n $n; done; echo ""
12345