[완료] bash 쉘 스크립트, "01"같이 0이 붙은 변수를 산술연산하려면?

jellypo의 이미지

로또 분석을 위해 bash shell script로 간단히 분석 프로그램을 만들고자 하였으나 각종 제약이나 알 수 없는 작동 때문에 어히려 c로 만드는 것보다 더 어려워졌습니다.

프로그램 아이디어는 다음과 같습니다.

1. 역대 로또 당첨 번호를 모두 배열에 넣는다.
2. 일정 기간 동안 나온 숫자 빈도를 deabak 배열에 저장. deabak 배열은 0~44까지의 배열로 1~45 숫자가 나오면 해당 숫자에 맞는 배열에 +1을 한다. 예를 들어 39가 나오면 deabak[38]+=1 하는 식으로.
3. deabak 배열 0~44까지를 출력. 해당 기간 동안 많이 나온 숫자, 적게 나온 숫자를 보며 대박 꿈을...

그런데 bash의 array는 이중배열도 안돼,

array[$i]=$j 이런 형태로 값을 넣는 것도 안되고
${array[$i]}=$j 이렇게 하면 명령어 실행으로 받아들이고

array=( [$i]=$j ) 이런 형태로 값을 넣어야 하더군요.

뭐 그렇긴 한데 문제는 로또 숫자를 넣은 array에 01, 02, 03...09로 저장해놓은 숫자가 문제더군요. 해당 숫자가 나오면

test.sh: line 243: 09: value too great for base (error token is "09")

이렇게 에러가 나네요.

#!/bin/bash
deabak=( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 )
array=(
10 23 29 33 37 40 16
09 13 21 25 32 42 02
11 16 19 21 27 31 30
14 27 30 31 40 42 02
16 24 29 40 41 42 03
14 15 26 27 40 42 34
02 09 16 25 26 40 42
08 19 25 34 37 39 09
02 04 16 17 36 39 14
09 25 30 33 41 44 06
01 07 36 37 41 42 14
02 11 21 25 39 45 44
22 23 25 37 38 42 26
02 06 12 31 33 40 15
03 04 16 30 31 37 13
06 07 24 37 38 40 33
03 04 09 17 32 37 01
03 12 13 19 32 35 29
06 30 38 39 40 43 26
10 14 18 20 23 30 41
06 12 17 18 31 32 21
04 05 06 08 17 39 25
05 13 17 18 33 42 44
07 08 27 29 36 43 06
02 04 21 26 43 44 16
04 05 07 18 20 25 31
01 20 26 28 37 43 27
09 18 23 25 35 37 01
01 05 13 34 39 40 11
08 17 20 35 36 44 04
07 09 18 23 28 35 32
06 14 19 25 34 44 11
04 07 32 33 40 41 09
09 26 35 37 40 42 02
02 03 11 26 37 43 39
01 10 23 26 28 40 31
07 27 30 33 35 37 42
16 17 22 30 37 43 36
06 07 13 15 21 43 08
07 13 18 19 25 26 06
13 20 23 35 38 43 34
17 18 19 21 23 32 01
06 31 35 38 39 44 01
03 11 21 30 38 45 39
01 10 20 27 33 35 17
08 13 15 23 31 38 39
14 17 26 31 36 45 27
06 10 18 26 37 38 03
04 07 16 19 33 40 30
02 10 12 15 22 44 01
02 03 11 16 26 44 35
02 04 15 16 20 29 01
07 08 14 32 33 39 42
01 08 21 27 36 39 37
17 21 31 37 40 44 07
10 14 30 31 33 37 19
07 10 16 25 29 44 06
10 24 25 33 40 44 01
06 29 36 39 41 45 13
02 08 25 36 39 42 11
14 15 19 30 38 43 08
03 08 15 27 29 35 21
03 20 23 36 38 40 05
14 15 18 21 26 36 39
04 25 33 36 40 43 39
02 03 07 17 22 24 45
03 07 10 15 36 38 33
10 12 15 16 26 39 38
05 08 14 15 19 39 35
05 19 22 25 28 43 26
05 09 12 16 29 41 21
02 04 11 17 26 27 01
03 12 18 32 40 43 38
06 15 17 18 35 40 23
02 05 24 32 34 44 28
01 03 15 22 25 37 43
02 18 29 32 43 44 37
10 13 25 29 33 35 38
03 12 24 27 30 32 14
17 18 24 25 26 30 01
05 07 11 13 20 33 06
01 02 03 14 27 42 39
06 10 15 17 19 34 14
16 23 27 34 42 45 11
06 08 13 23 31 36 21
02 12 37 39 41 45 33
04 12 16 23 34 43 26
01 17 20 24 30 41 27
04 26 28 29 33 40 37
17 20 29 35 38 44 10
01 21 24 26 29 42 27
03 14 24 33 35 36 17
06 22 24 36 38 44 19
05 32 34 40 41 45 06
08 17 27 31 34 43 14
01 03 08 21 22 31 20
06 07 14 15 20 36 03
06 09 16 23 24 32 43
01 03 10 27 29 37 11
01 07 11 23 37 42 06
01 03 17 32 35 45 08
17 22 24 26 35 40 42
05 14 15 27 30 45 10
17 32 33 34 42 44 35
08 10 20 34 41 45 28
04 10 12 22 24 33 29
01 04 05 06 09 31 17
07 18 22 23 29 44 12
01 05 34 36 42 44 33
07 20 22 23 29 43 01
07 18 31 33 36 40 27
26 29 30 33 41 42 43
04 09 28 33 36 45 26
11 14 19 26 28 41 02
01 02 06 09 25 28 31
02 04 25 31 34 37 17
05 10 22 34 36 44 35
03 04 10 17 19 22 38
03 11 13 14 17 21 38
04 06 10 11 32 37 30
12 28 30 34 38 43 09
01 11 16 17 36 40 08
07 17 18 28 30 45 27
04 16 23 25 29 42 01
02 08 32 33 35 36 18
07 20 22 27 40 43 01
03 05 10 29 32 43 35
12 30 34 36 37 45 39
19 23 25 28 38 42 17
07 19 24 27 42 45 31
08 10 11 14 15 21 37
03 17 23 34 41 45 43
04 07 15 18 23 26 13
03 12 20 23 31 35 43
06 14 22 28 35 39 16
02 16 30 36 41 42 11
07 09 20 25 36 39 15
10 11 27 28 37 39 19
09 11 15 20 28 43 13
03 13 17 18 19 28 08
08 12 29 31 42 43 02
12 16 30 34 40 44 19
26 27 28 42 43 45 08
04 15 17 26 36 37 43
02 03 13 20 27 44 09
02 19 27 35 41 42 25
04 06 13 21 40 42 36
21 25 33 34 35 36 17
02 11 21 34 41 42 27
02 18 25 28 37 39 16
01 02 10 13 18 19 15
01 05 13 26 29 34 43
03 08 11 12 13 36 33
06 19 21 35 40 45 20
16 19 20 32 33 41 04
05 18 28 30 42 45 02
19 26 30 33 35 39 37
04 09 13 18 21 34 07
01 18 30 41 42 43 32
03 07 08 34 39 41 01
22 34 36 40 42 45 44
01 05 21 25 38 41 24
07 11 26 28 29 44 16
06 09 10 11 39 41 27
05 13 18 19 22 42 31
09 12 27 36 39 45 14
24 27 28 30 36 39 04
03 10 31 40 42 43 30
16 27 35 37 43 45 19
02 11 13 15 31 42 10
04 16 25 29 34 35 01
04 19 21 24 26 41 35
03 09 24 30 33 34 18
13 14 18 22 35 39 16
19 26 28 31 33 36 17
04 17 30 32 33 34 15
01 10 13 16 37 43 06
01 05 11 12 18 23 09
05 09 17 25 39 43 32
02 15 20 21 29 34 22
14 21 23 32 40 45 44
13 15 27 29 34 40 35
02 18 24 34 40 42 05
01 02 06 16 20 33 41
01 02 04 08 19 38 14
04 10 14 19 21 45 09
01 02 08 18 29 38 42
19 24 27 30 31 34 36
08 14 32 35 37 45 28
08 14 18 30 31 44 15
05 06 24 25 32 37 08
04 08 11 18 37 45 33
06 14 18 26 36 39 13
15 20 23 26 39 44 28
07 10 19 22 35 40 31
35 36 37 41 44 45 30
07 12 16 34 42 45 04
12 19 20 25 41 45 02
14 21 22 25 30 36 43
05 06 13 14 17 20 07
03 11 24 38 39 44 26
12 14 27 33 39 44 17
01 03 11 24 30 32 07
03 12 14 35 40 45 05
01 03 21 29 35 37 30
01 02 03 15 20 25 43
03 11 14 31 32 37 38
14 25 31 34 40 44 24
02 07 18 20 24 33 37
10 19 22 23 25 37 39
12 13 17 20 33 41 08
11 12 18 21 31 38 08
02 03 04 05 20 24 42
05 07 20 25 28 37 32
02 03 07 15 43 44 04
07 16 17 33 36 40 01
16 20 27 33 35 39 38
01 08 14 18 29 44 20
04 11 20 26 35 37 16
05 11 19 21 34 43 31
02 20 33 35 37 40 10
05 07 28 29 39 43 44
01 03 18 20 26 27 38
04 19 26 27 30 42 07
05 11 13 19 31 36 07
02 06 08 14 21 22 34
04 05 15 16 22 42 02
17 25 35 36 39 44 23
04 05 09 11 23 38 35
05 11 14 29 32 33 12
05 10 19 31 44 45 27
)
len=${#array[*]}
 
 
i=0
 
while [ $i -le $len ]
do
  array[$i]=$((array[$i]+0))
  i=$(($i+1))
done
 
echo ${array[@]}

개선된 쉘 스크립트

배열부분 생략
#검색할 회차 입력
read range1
read range2
 
start=$(( ($range1-1) * 7 ))
end=$(( $range2*7 - 1 ))
 
 
#입력한 기간 동안 당첨번호를 출력
while [ $start -le $end ]
do
  echo "${array[$start]} "
 
  start=$(( $start + 1 ))
done

실행방법 및 결과

jellypo@JellyKing:~$ bash lotto | perl -pe 's/ /\n/g' | sort -n | uniq -c | sort -n
1 (입력)
20 (입력)
      1 08
      1 18
      1 20
      1 22
      1 35
      1 43
      1 45
      2 01
      2 07
      2 10
      2 11
      2 12
      2 15
      2 17
      2 24
      2 34
      2 36
      2 44
      3 04
      3 13
      3 19
      3 21
      3 23
      3 27
      3 29
      3 32
      3 38
      4 03
      4 06
      4 26
      4 31
      4 33
      4 39
      4 41
      5 09
      5 14
      6 02
      6 16
      6 25
      6 30
      7 37
      7 42
      8 40
    140

앞의 숫자가 빈도, 뒤의 숫자가 당첨 번호입니다.

최종버전
deabak.sh 스크립트 파일
lotto 로또 당첨번호 모음, 한 줄이 각 회에 해당함. 첫째줄이 1회, 끝줄(231라인)이 최근인 231회 번호. 일곱번째 숫자는 행운번호인데 일단 같이 취급함.

deabak.sh

#1/bin/bash
echo $1 $2
sed -n "$1,$2p" lotto| tr ' ' '\n' | sort -n | uniq -c | sort -n

사용방법은 커맨드 라인에서
./deabak.sh 12 30
12회부터 30회까지 당첨번호 출현빈도 검색

7339989b62a014c4ce6e31b3540bc7b5f06455024f22753f6235c935e8e5의 이미지

이런 작업을 굳이 쉘 스크립트로 해야 하는 이유가 있나요?
파이썬이나 루비나 펄 같은 좋은 스크립팅 언어가 많이 있잖아요. :-)

jellypo의 이미지

1. 쉘 스크립트로 시작해버려서
2. 펄은 어느정도 아는데 루비/파이썬은 전혀 몰라서
3. 저도 C로 시작할걸 하는 후회가 ...;

제가 할 줄 아는건 C, bash, perl 정도밖에 없어요.;

bushi의 이미지

할 수 있으니까.

http://www.faqs.org/docs/bashman/bashref_71.html

상략...
 
while [ $i -le $len ]
do
  index=`expr ${array[$i]} + 0`
  value=`expr ${deabak[$index]} + 1`
  deabak[$index]=$value
  let i=i+1
done
 
echo ${deabak[@]}

느려요.

[bushi@rose net]$ time ./test.sh
1 47 45 41 40 35 36 40 35 26 34 37 27 32 40 32 35 42 38 39 37 33 25 29 27 38 39 39 27 32 37 35 30 42 37 43 41 44 29 40 38 27 41 39 36 31
 
real    0m8.963s
user    0m2.519s
sys     0m6.092s
[bushi@rose net]$
bushi의 이미지

deabak 배열은 09 따위가 될 리가 없으므로..

[bushi@rose net]$ diff -uN test.orig.sh test.sh
--- test.orig.sh        2007-05-08 23:48:36.000000000 +0900
+++ test.sh     2007-05-08 23:49:33.000000000 +0900
@@ -240,7 +240,7 @@
 while [ $i -le $len ]
 do
   index=`expr ${array[$i]} + 0`
-  value=`expr ${deabak[$index]} + 1`
+  let value=${deabak[$index]}+1
   deabak[$index]=$value
   let i=i+1
 done
[bushi@rose net]$
[bushi@rose net]$ time ./test.sh
1 47 45 41 40 35 36 40 35 26 34 37 27 32 40 32 35 42 38 39 37 33 25 29 27 38 39 39 27 32 37 35 30 42 37 43 41 44 29 40 38 27 41 39 36 31
 
real    0m4.134s
user    0m1.349s
sys     0m2.563s
[bushi@rose net]$

절반 정도로 줄었...
뭔가를 실행시키지 않고 0을 떼버릴 방법이 있을까요 ?
bushi의 이미지

버그수정

[bushi@rose net]$ diff -uN test.bug.sh test.sh
--- test.bug.sh 2007-05-09 00:22:30.000000000 +0900
+++ test.sh     2007-05-09 00:21:05.000000000 +0900
@@ -237,9 +237,9 @@
 
 i=0
 
-while [ $i -le $len ]
+while [ $i -lt $len ]
 do
-  index=`expr ${array[$i]} + 0`
+  index=`expr ${array[$i]} - 1`
   let value=${deabak[$index]}+1
   deabak[$index]=$value
   let i=i+1
[bushi@rose net]$
[bushi@rose net]$ time ./test.sh
47 45 41 40 35 36 40 35 26 34 37 27 32 40 32 35 42 38 39 37 33 25 29 27 38 39 39 27 32 37 35 30 42 37 43 41 44 29 40 38 27 41 39 36 31 0
 
real    0m4.840s
user    0m1.481s
sys     0m2.887s
[bushi@rose net]$

jellypo의 이미지

bash 스크립트가 형 변환을 스스로 하고, 강제 형변환을 할 수 없게 해놓아서 다른 방법이 없는거 같네요.

제가 문제 해결방법에 따른 수단을 잘못 택한거 같습니다.;; 저기 밑에 sed 혹은 perl로 간단히 하시는 분들 보고 쓰러지는 중.

무단포옹의 이미지

엄밀히 말하면 shell script는 아닙니당.

$ time cat test.list | perl -pe 's/ /\n/g' | sort -n | uniq -c
... 중략
real    0m0.087s
user    0m0.049s
sys     0m0.036s

test.list 는 로또 데이터 부분만 추출한 파일입니다

무단포옹의 이미지

한번 더 소트하면!

time cat test.list | perl -pe 's/ /\n/g' | sort -n | uniq -c | sort -n

빈도별로 오름차순으로 나옵니다.
무단포옹의 이미지

한번 더 소트하면!

time cat test.list | perl -pe 's/ /\n/g' | sort -n | uniq -c | sort -n

빈도별로 오름차순으로 나옵니다.
jellypo의 이미지

중요한걸 깜빡했네요.

일정 기간 동안의 숫자 빈도를 위해 이 프로그램을 만들고 있었습니다. 예를 들면 200회부터 231회까지 1-45각 숫자가 몇 번 나왔는지 알아보려고요. 당첨번호 리스트를 검색할 때마다 손봐야 하는건 불편해서 스크립트로 입력받을 값을 편하게 받을 수 없을까 해서 시작했고요.

좀 정리해서 소스 올릴게요.

alfalf의 이미지

sed -n '시작위치,$p' list.txt | tr ' ' '\n' | sort -n | uniq -c | sort -n
jellypo의 이미지

!!!!!!!!!!!!!!

라인 선택만 하면 되는건가요? info sed 보는 중.

sed -n -e '1,2p' lotto

이렇게 하면 선택된 라인만 출력하는게 가능하네요. (여기서는 1번째 2번째 라인)

'시작위치,$p'은 시작위치부터 $ 파일 끝까지를 p 출력한다는 의미였네요. 이걸 이해 못해서 '$p'로 봤거든요. 따로인걸 몰랐음.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.