저는 스크립팅을 처음 접했고 제 임무는 100개를 찾는 것입니다.회문다음 알고리즘을 사용하는 숫자:
- 두 개의 난수를 얻습니다(10보다 큼).
- 역방향 숫자
- 숫자와 그 역수 더하기
- 합의 결과가 회문이면 인쇄하십시오. 그렇지 않으면 2단계로 돌아가세요.
예를 들어:
- 시작 수량: 75
- 뒷면은 57입니다
- 합계는 75+57 = 132입니다.
132는 회문 번호가 아니므로 2단계로 돌아갑니다.
- 그 반대는 321이다.
- 132 + 321 = 363
- 363은 회문수이다. 표준 출력으로 인쇄하세요!
그리고 그러한 숫자가 100개까지 인쇄될 때까지 계속됩니다.
이것이 내가 지금까지 가지고 있는 것입니다:
#! /bin/bash
CONT=0
while [ $CONT -lt 100 ]
do
NUM= $RANDOM
while [ $SUM -ne $SUMINV ]
do
echo $NUM > file.txt
INV= rev file.txt
SUM= `expr[ $NUM + $INV ]`
echo $SUM > file2.txt
SUMINV= rev file2.txt
NUM= $SUM
done
echo $NUM
CONT=`expr $CONT + 1`
done
이 스크립트에 대한 솔루션과 도움을 찾고 있습니다!
답변1
제가 알기로는 먼저 두 자리 숫자를 받아야 합니다.
- 10보다 크다 100보다 작다
- 10으로 나누지 않음(20, 30 등은 아님)
- 회문이 아님(22,33 등이 아님)
그래서 당신은 그것을 통해 도달 할 수 있습니다
while :
do
a=$[$RANDOM%10]
b=$[$RANDOM%10]
if [ $a -ne $b -a $a -ne 0 -a $b -ne 0 ]
then
NUM="$a$b"
RNUM="$b$a"
break
fi
done
다음으로 숫자의 합과 반전을 확인하세요.
while :
do
NUM=$[$NUM+$RNUM]
RNUM=$(printf "%d" $NUM | rev)
if [ $NUM -eq $RNUM ]
then
echo $NUM
break
fi
done
답변2
원본 스크립트에 다양한 구문 오류가 있습니다. 예를 들어 foo= bar
, Bash에서는 공백이 중요합니다. 당신은해야합니다 foo=bar
. 또한 명령의 출력을 얻으려면 이 작업을 수행할 수 없으며 foo=command
명령을 백틱으로 묶어야 합니다 foo=$(command)
. 또는 더 나은 방법은 다음과 같습니다. 작업 버전은 다음과 같습니다.
#!/usr/bin/env bash
CONT=0
## This array will hold the numbers we've seen
## uncomment this line for unique numbers
#declare -a seen;
while [ "$CONT" -lt 100 ]
do
## Get a random number
NUM=$RANDOM
## Make sure it is < 100
let "NUM %= 100"
## Make sure the number is more than 10
while [ "$NUM" -le 10 ]
do
NUM=$((NUM+1))
done
## In case the addition made it longer than two digits
NUM="${NUM:0:2}"
## Make sure the number does not end in 0
## If it does, we will get an error when
## attempting to add it. Bash doesn't
## like leading 0s.
[[ $NUM =~ 0$ ]] && let NUM++
## Sum the number and its reverse
SUM=$((NUM+$(rev <<<$NUM)));
## Is this a palindrome?
if [ "$SUM" = "$(rev <<<$SUM)" ]
then
## You did not say if you wanted 100 different
## numbers. If so, uncomment these lines
#let seen[$SUM]++
## If this number has not been seen before
#if [ "${seen[$SUM]}" -eq 1 ]
# then
## print it
echo $SUM
## increment the counter
let CONT++
#fi
fi
done
스크립트는 숫자를 있는 그대로 반복합니다. 고유 번호를 얻으려면 스크립트 주석에 설명된 대로 이 줄의 주석 처리를 제거하세요.
답변3
이것은 흥미 롭습니다. 나는 이 질문을 좋아한다. 작업을 수행하기 위해 다음 함수를 작성했고 작업이 완료되었습니다.
palindromes() (
rev() while getopts : o "-$1" ||
! r="${2#"${2%%[1-9]*}"}"
do set -- "$1" "$OPTARG$2"
done
rand() { : & : "$(($1=$!))"; }
[ "$1" -gt 10 ] || exit
n=$1; set --
while OPTIND=1; rev "$n"
case "$#.$n.$r" in
(100.*) ! printf '%s\t%s\t%s\t%s\t%s\n' "$@" ;;
(*.$r.$n) set -- "$@" "$n"; rand n ;;
(*) n=$((${n#-}+${r%-})) ;;
esac; do :; done
)
이에 대해 주목할 만한 몇 가지 사항이 있습니다. 첫째, getopts
숫자를 반전시키기 위한 것입니다. 의 주요 기능은 getopts
모두 함께 연결될 수도 있고 그렇지 않을 수도 있는 짧은 옵션을 구문 분석하는 것입니다. 따라서 문자열의 각 바이트를 반복하는 데 편리한 도구가 됩니다.
$RAND
나는 쉘 의 기능을 별로 좋아하지 않지만 백그라운드에서 아무 작업도 수행하지 않고 첫 번째 인수에 저장된 varname에 무효화된 PID를 할당하는 bash
내 기능보다 더 보수적일 것입니다 . rand()
인정해요, 꽤 저렴해요.
이 case
구조를 사용하면 간단한 테스트를 통해 과제의 모든 측면을 쉽게 평가할 수 있습니다. 나는 다음을 원한다:
case "$#.$n.$r" in
(100*) all done; printf %s\\n "$@";;
(*$r.$n) palindrome; set -- "$@" "$n";;
(*) no luck; $n+$r; go again;;
esac
처음에는 이것 때문에 많은 어려움을 겪었습니다. 처음에 나는 다음과 같은 일을 하고 있었습니다.
(*$r.$n) set -- ...; n=$((n+1))
그건나쁜아이디어. 런어웨이 덧셈은 단순히 숫자를 세는 것만으로도 회문을 찾을 가능성을 제거하기에 충분할 정도로 숫자를 즉시 증가시킵니다. 엉망이 되었지만 date +%S
다른 프로세스를 실행하려면 그냥 PID를 사용하는 편이 낫겠다고 생각했습니다. 이 경우 프로세스가 아무런 작업도 수행하지 않을 수도 있습니다. 그럼에도 불구하고 PID 범위는 거의 매번 폭주 요인을 제어할 수 있을 만큼 작습니다.
예를 들어 지금 실행하고 결과를 붙여넣겠습니다.
palindromes 76
산출
484 29292 49294 69296 89298
215512 50605 90609 446644 886688
123321 52625 92629 468864 663787366
134431 54645 94649 881585188 7667585634365857667
145541 23432 43434 63436 83438
147741 24442 44444 64446 84448
158851 25452 45454 65456 85458
169961 13231 46464 66466 86468
49985258994 27472 47474 67476 87478
14355341 28482 48484 68486 88488
395593 29492 49494 69496 89498
219912 121121 11244211 441144 881188
125521 165561 15522551 463364 7365409856589045637
136631 211112 17858768886785871 485584 893974888888479398
147741 23632 43634 63636 83638
149941 24642 44644 64646 84648
523325 25652 45654 65656 85658
567765 13331 46664 66666 86668
2358532 27672 47674 67676 87678
2236322 28682 48684 68686 88688
아마도 사기꾼이 있을 것입니다. 분명히 그런 일이 발생합니다. 별로. 이것이 당신에게 문제가 되는지 모르겠지만, 이것은 그것이 어떻게 이루어질 수 있는지를 보여주는 예일 뿐입니다.
마지막 참고 사항 - 차이가 1초 정도인 것처럼 보이지만 이를 실행하는 것이 dash
에서 실행하는 것보다 훨씬 빠릅니다 . bash
어떤 경우 에라도,당신이 그렇게한다면사용하려면 줄을 다음으로 변경 dash
해야합니다 .rev()
set -- "$1"
set -- "${1#?}".
나는 방금 두 자리 요구 사항이 있다는 것을 깨달았습니다. 비록 이 특정 규칙이 과제가 너무 어려워지는 것을 방지하기 위한 것이라고 생각합니다. 어쨌든, 문자열의 하위 집합만 얻는 것은 쉽습니다. 실제로 이것은 r=
다음 상황에서 내가 한 일입니다.
r="${2#"${2%%[1-9]*}"}"
r
...항상 0으로 시작하지 않는 값을 할당합니다 .
rand()
항상 두 자리 숫자를 할당하는 버전은 다음과 같습니다 $1
.
rand() { : & set -- "$1" "$!" "$(($!%100))"
: "$(($1=($3>10?$3:${#2}$3)))"
}
물론 bash
's'에도 동일한 논리를 적용할 수 있습니다. $RAND
삼항 $((var=(value)?(assign if true):(assign if false)))"
연산자는 거의 모든 정수 집합에 대해 작동합니다. 여기서는 모듈로 100을 할당합니다.(기본적으로 백분위수)값이 10보다 크면 두 자리 중 두 번째 자리로 지정합니다. 여기서 첫 번째 자리는 count 의 자리 수입니다 $!
.
이런 식으로 실행하면 결과가 덜 흥미로워집니다.
333 66 484 1111 4884
77 88 99 121 121
363 484 77 4884 44044
88 99 121 121 363
484 1111 4884 88 8813200023188
99 121 121 363 484
1111 4884 44044 8813200023188 99
44 55 66 77 44
99 121 121 363 484
424 11 33 44 55
66 77 88 99 121
22 33 22 55 66
77 88 99 121 121
33 44 55 33 77
88 99 121 121 363
44 55 66 77 44
99 121 121 363 484
55 66 77 88 99
55 121 363 484 1111
66 77 88 99 121