Language detail: Bash

Coverage: 46.10%
number of '+' ratings
contribution for coverage

Unsolved challenges

codes

Feed

Used modules

next >>

π (Nested Flatten)
前半は半径rの1/4円の面積aを求めています。
後半では面積aを単純に4倍し、r*rで割ってpiを求めたかったのですが、
bashでは小数を持てないので、小数部分を10倍しながら表示しています。

$ ./pi.sh 100
3.1416
$ ./pi.sh 241
3.1400974
$ ./pi.sh 1000
3.141548
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#/bin/bash

r="$1"
a=0

for ((x=1;x<=r;x++)) {
    for ((y=0;y<r;y++)) {
        if ((x*x+y*y<=r*r));then
            a=$((a+1))
        else break
        fi
    }
}

z=$((a*4));m=$((z/(r*r)))
echo -n $m
z=$((z-m*r*r))
if ((z));then
    echo -n .
fi
for ((i=1;i<8&&z>0;i++)) {
    n=$((z*10/(r*r)))
    z=$((z*10-n*r*r))
    echo -n $n
}
echo
数値リストの圧縮 (Nested Flatten)
$ compact_number_list 1 3 4 5 6 12 13 15 20 25 26 27
[ 1 [ 3 6 ] 12 13 [ 15 25 5 ] 26 27 ]
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
function compact_number_list() {
    echo -n '[ '
    while (($# > 0));do
        if (($# >= 3)) && (($2 - $1 == $3 - $2));then
            local d=$(($2 - $1))
            echo -n "[ $1 "
            shift 2
            while (($# >= 2)) && (($2 - $1 == d));do
                shift
            done
            echo -n "$1 "
            ((d != 1)) && echo -n "$d "
            echo -n '] '
        else
            echo -n "$1 "
        fi
        shift
    done
    echo ']'
}
タブ区切りデータの処理 (Nested Flatten)

sortを使いawkを使わない解。bashとdashで動作確認。

1、3、4、5行目にはタブ文字が含まれています。

1
2
3
4
5
6
IFS='    '
read -r id forename surname age
echo "$id    $surname    $forename    $age"
sort -n -t '    ' | while read -r id forename surname age;do
    echo "$id    $surname    $forename    $((age + 1))"
done
2^i * 3^j * 5^k なる整数 (Nested Flatten)

配列の添字が冗長だったので微修正します。

1
2
3
4
5
6
7
8
n=1
for ((i = 0; i < 100; i++));do
    echo $n
    ary[n*2]=1
    ary[n*3]=1
    ary[n*5]=1
    while [ "${ary[++n]}" != 1 ];do :;done
done

アプローチとしては#7638と同じでしょうか。配列。

1
2
3
4
5
6
7
8
n=1
for ((i = 0; i < 100; i++));do
    echo $n
    ary[$((n*2))]=1
    ary[$((n*3))]=1
    ary[$((n*5))]=1
    while [ "${ary[$((++n))]}" != 1 ];do :;done
done
メソッドのフック (Nested Flatten)

bashやPOSIX-shでは、外部コマンドや内部コマンドよりシェル関数が優先して呼ばれます。いっぽう、commandコマンドを使うことにより、シェル関数を省いて外部コマンドや内部コマンドを呼べます。

これを組み合わせると、下のコードのようにして、外部コマンドをシェル関数でフックできます。

ただし、シェル関数はこの方法ではフックできません。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
ls() {
    # before
    echo '***** start *****'

    # command itself
    command ls "$@"
    local result=$?

    # after
    echo '***** end *****'

    return $result
}
起動オプションの解析 (Nested Flatten)

#7614の訂正にしたがって簡略化してみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash
while getopts 'oqd:*' opt;do
    case "$opt" in
    o)  opt_o=ON ;;
    q)  opt_q=ON ;;
    d)  opt_d=$OPTARG
        [[ $opt_d == [012] ]] || exit 1
        ;;
    esac
done
shift $((OPTIND - 1))

[ -z "$opt_o" ] && exit 1
[ $# = 0 ] && exit 1

echo "[オプション情報]
o(output): ON
q(quote):  ${opt_q:-OFF}
d(debug):  ${opt_d:-}

[パラメータ情報]
指定数: $#"

i=0
for e in "$@";do
    echo "$((++i)): $e"
    shift
done

pure bashで内蔵コマンドgetoptsを使いました。

起動例の-sはコマンドじゃなくて引数扱い、と解釈したために、その部分がBKっぽくなっています。

あと、-oは必須ということで、そこの出力は手抜きしています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#!/bin/bash
OPTERR=0

args=()
nargs=0

opt_o=OFF
opt_q=OFF
opt_d=''

while [ $# != 0 ];do
    oprind_orig=$OPTIND
    while getopts 'oqd:*' opt;do
        case "$opt" in
        o)  opt_o=ON
            ;;
        q)  opt_q=ON
            ;;
        d)  opt_d=$OPTARG
            [[ $opt_d == [012] ]] || exit 1
            ;;
        \?) [[ ! ${!OPTIND} == -* ]] && ((OPTIND--))
            break
            ;;
        esac
    done
    shift $((OPTIND - 1))
    OPTIND=1
    [ $# != 0 ] && args[$((nargs++))]=$1
    shift
done

[ "$opt_o" = OFF ] && exit 1
((nargs)) || exit 1

echo "[オプション情報]
o(output): ON
q(quote):  $opt_q
d(debug):  $opt_d

[パラメータ情報]
指定数: $nargs"

for ((i = 0; i < nargs; i++));do
    echo "$((i + 1)): ${args[$i]}"
done
LL Golf Hole 9 - トラックバックを打つ (Nested Flatten)

LL Futureゴルフコースありがとうございました。楽しませていただきました。

今回も無駄にpure bashで書いてみます。

enable-net-redirectionsつきでビルドされたbashで、UTF-8のソース前提です。

# 同じurlパラメータからだと、サーバーから既出だとツッコまれますね、当然ながら

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
function urlencode() {    # just workaround
    local s=$1
    s=${s// /+}
    echo "${s//
/%0A}"
}

function http_post() {
    local host=$1
    local path=$2
    local post_data=$3
    local LANG=C

    exec 3<> "/dev/tcp/$host/80"

    (
    echo -e "POST $path HTTP/1.0\r"
    echo -e "Host: $host\r"
    echo -e "Content-Length: ${#post_data}\r"
    echo -e 'Content-Type: application/x-www-form-urlencoded; charset=utf-8\r'
    echo -e '\r'
    echo "$post_data"
    ) >&3

    local s
    read -d '' s <&3
    echo "$s"

    exec 3>&-
    exec 3<&-
}

function trackback() {
    local host=$1
    local path=$2
    local title=$(urlencode "$3")
    local url=$4
    local blog_name=$(urlencode "$5")

    local excerpt
    read -d '' excerpt
    excerpt=$(urlencode "$excerpt")

    http_post "$host" "$path" \
      "title=$title&url=$url&blog_name=$blog_name&excerpt=$excerpt"
}

trackback 'll.jus.or.jp' '/2008/blog/archives/38/trackback' \
  'LL Future参加' 'http://ja.doukaku.org/207/' 'LL Future Hole 9' <<'__EOT__'
LL Futureに行ってきました!
楽しかった! 自分の回答がスクリーンに出た><
__EOT__
/*コメント*/を取り除く (Nested Flatten)

内蔵コマンドのみのpure bashで。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
function remove_comment() {
    local str=$1

    while [[ $str == */\** ]];do
        echo -n ${str%%/\**}
        str=${str#*/\*}
        if [[ $str == *\*/* ]];then
            str=${str#*\*/}
        else
            str=''
        fi
    done
    echo $str
}

remove_comment 'AAA'
remove_comment 'AAA/*BBB*/'
remove_comment 'AAA/*BBB'
remove_comment 'AAA/*BBB*/CCC'
remove_comment 'AAA/*BBB/*CCC*/DDD*/EEE'
remove_comment 'AAA/a//*BB*B**/CCC'
固定長データ (Nested Flatten)

内蔵コマンドのみのpure bashで。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
shopt -s extglob
declare -i age

function readRecord() {
    local n=$1
    local s d

    read -n 12 s
    family_name[$n]=${s%%+( )}

    read -n 12 s
    first_name[$n]=${s%%+( )}

    read -n 1 sex[$n]
    read -n 3 age[$n]
    read -n 4 year[$n]
    read -n 2 mon[$n]

    for ((d = 0; d < 31; d++));do
        eval read -n 2 date_$d[$n]

        read -n 500 s
        eval "breakfast_$d[$n]='${s%%+( )}'"

        read -n 500 s
        eval "lunch$d[$n]='${s%%+( )}'"

        read -n 500 s
        eval "dinner_$d[$n]='${s%%+( )}'"
    done
}

for ((i = 0; i < 500; i++));do
    readRecord $i
done < data.txt
2次元ランダムウォーク (Nested Flatten)

上下左右のみの単純実装です。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
dx=(1 0 -1 0)
dy=(0 1 0 -1)
x=0
y=0
i=0
while :;do
    echo $((i++)) $x $y
    ((r = RANDOM % 4))
    ((x += dx[r]))
    ((y += dy[r]))
done
環境変数の取得 (Nested Flatten)

bashで、exportされてないシェル変数を避けて環境変数の一覧を表示する方法には「printenv」「env」「export -p」があります。このうちexportはbash内蔵コマンドです。

特定のキーから環境変数の値を得るには、printenvに環境変数名を与えます。

蛇足として、内蔵コマンドだけで「printenv 変数名」相当のことをするコマンド(関数)を定義してみます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# 環境変数一覧は以下のどれかで
printenv
env
export -p

# キーから値を得るには、printenvで
prinetnv 'HOME'

# printenvは外部コマンドだからという方には、pure bashで
myprintenv1() {
    local name=$1
    local a b str
    export -p | while read a b str;do
        if [ ${str%%=*} = "$name" ];then
            str=${str#*=\"}
            echo ${str%\"}
            break
        fi
    done
}
設定ファイルから値を取得 (Nested Flatten)

お題のShowPrice.iniに合わせた回答です。

1
2
3
4
5
showPrice() {
    local ITEM_NAME ITEM_COST 
    . ShowPrice.ini
    echo "「$ITEM_NAME」は$((ITEM_COST + ITEM_COST * 5 / 100))円(税込み)"
}
文字列型日時ののN秒後時間取得 (Nested Flatten)

仕様2を満たしていませんでした。

修正と、ついでに1引数に対応。

1
2
3
4
5
6
7
8
DateEx() {
  [ -z "$2" ] && set '' $1
  if [[ $2 == -* ]];then
    date -d "$1 ${2:1} seconds ago"
  else
    date -d "$1 $2 seconds"
  fi
}
1
2
3
DateEx() {
  date -d "$1 $2 seconds"
}
LL Golf Hole 8 - 横向きのピラミッドを作る (Nested Flatten)

空気を読まずにネタ回答。

設問からは外れてないはず。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
stty raw
tput clear
for ((i=$1*2-1;i>0;i--));do
  for ((j=0;j++<i;));do
    echo -n \*
    tput cub1
    tput cud1
  done
  tput cuf1
  tput cuu $((--i))
done
tput cud $1
stty cooked

pure bash。86B。

1
2
3
4
while ((i++<$1**2));do
  echo -n \*
  ((++j>m))&&echo&&((j=0,i<($1+1)*$1/2?m++:m--))
done
LL Golf Hole 7 - バイト数を読みやすくする (Nested Flatten)

pure bashで正攻法。

引数→標準出力。インデントを削って108B。

1
2
3
4
5
6
7
n=$1
set 0 k M G T
while [ $n -gt 999 -a -n "$2" ];do
  shift
  ((m=n/100%10,n=n/1000))
done
echo $n${m:+.$m$1}
LL Golf Hole 3 - 13日の金曜日を数え上げる (Nested Flatten)

cal 使うといいんじゃないですかねぇ。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
eval `date '+y=%Y;m=$((%-m+(%e>13)))'`
for i in `seq $y 2013`;do
for j in `seq $m 12`;do
if [ `cal $j $i|awk '$6==13&&$_=$6'` ];then
c=$((c+1))
printf $i-%02d-13\\n $j
fi
done
m=1
done
echo $c
next >>

Index

Feed

Other

Link

Pathtraq

loading...