다음은 성능 문제가 많은 스크립트입니다.
#!/usr/bin/ksh
while read i
do
x=`echo $i |cut -d"|" -f2`
rem=`expr $x % 62`
echo "reminder is " $rem
quo=`expr $x / 62`
echo "quotiont is " $quo
grp_rem=" "
if [[ ${#quo} -ge 2 ]]
then
while [ $quo -ge 62 ]
do
sub_rem=`expr $quo % 62`
quo=`expr $quo / 62`
grp_rem=`echo $sub_rem" "$grp_rem`
done
fi
echo $i"|"$quo" "$grp_rem" "$rem >> base62_while.out
done < base62_while.txt
어쨌든 위 스크립트를 사용하여 성능을 향상시킬 수 있습니까?
입력 예:
1|5147634738948389685
샘플 출력
1|5147634738948389685|6 8 16 13 46 17 20 35 9 49 43
답변1
외부 도구를 호출할 필요가 없습니다. ksh가 산술을 수행할 수 있습니다. 또한 나머지를 저장하기 위해 배열을 사용합니다.
#!/usr/bin/ksh
div=62
while IFS='|' read -r n x; do
rem=$(( x % div ))
quo=$(( x / div ))
echo "reminder is $rem" >&2
echo "quotiont is $quo" >&2
remainders=( $rem )
while (( quo >= div )); do
sub_rem=$(( quo % 62 ))
quo=$(( quo / 62 ))
echo "reminder is $sub_rem" >&2
echo "quotiont is $quo" >&2
remainders=( $sub_rem "${remainders[@]}" )
done
echo "$n|$x|$quo ${remainders[*]}"
x=$quo
for r in "${remainders[@]}"; do
x=$(( x * div + r ))
done
echo Verification: $x
done <<END
1|5147634738948389685
END
답변2
훨씬 빨라야 해요
#!/usr/bin/ksh
#
while IFS='|' read n x
do
base62="$(echo "obase=62; $x" | bc | sed -re 's/ 0/ /g' -e 's/^ //')"
printf "%d|%s|%s\n" $n "$x" "$base62"
done <base62_while.txt >>base62_while.out
이 base62
줄은 bc
10진수 소스 숫자를 해당하는 기본 62 숫자로 변환합니다. 선행 0을 제거하는 두 자리 십진수 쌍을 출력합니다(즉 , 02
로 다시 작성 2
하지만 45
변경되지 않은 상태로 유지).
입력하다
1|5147634738948389685
산출
1|5147634738948389685|6 8 16 13 46 17 20 35 9 49 43
답변3
수행할 수 있는 작업(및 속도 향상)은 다음과 같습니다.
- 원래 1000개 숫자
35.023초 - 모든 expr 명령을 산술 확장으로 대체 $((x%62))
14.473 -
3.131
grp_rem=`echo $sub_rem" "$grp_rem`
로 변환grp_rem="$sub_rem $grp_rem"
- cut(
set IFS='|'; set -f
; 및set -- $1
) 을 사용하여 쉘 분할을 사용하지 마십시오.IFS='|' read a x <<<"$i"
또는 (<<<
임시 파일을 생성하는 동안) 사용- 이미 사용되었으므로 읽기를 교체하십시오.
0.454
- 하나의 루프로 줄이고(if 제거) 끝에 후행 공백
0.207을 제거합니다. $((...))
두 개의 0.113 ---- 쉘을 연결하는 루프를 더 단단하게 만듭니다
. 변경 시간은 35.023초보다 약 300배 빠릅니다.
++++ 이것은 아마도 쉘 스크립트로 할 수 있는 가장 좋은 일일 것입니다.- awk 0.123으로 변경
---- awk: 전체 변경 사항이 약 280배 빨라졌습니다.
결과 스크립트:
#!/usr/bin/ksh
while IFS='|' read a b # read both values split on '|'
do
x=$b # set value of x (quotient)
grp_rem="" # clear value of group
while (( rem=x%62 , x/=62 )) # do both math expressions.
do
grp_rem="$rem $grp_rem" # concatenate resulting values
done
grp_rem=${grp_rem%?} # remove one character (an space)
echo "$a|$b|$rem $grp_rem"
done < base62_while.txt >> base62_while.out
awk 스크립트와 동일합니다. 이것이 더 빠른 awk 스크립트인지는 모르겠지만 잘 작동합니다. 쉘보다 10,000개 이상의 라인이 빠릅니다.
노트:-M
이는 제공한 19자리 순서대로 숫자를 처리하는 데 필요한 (임의 정밀도) 옵션과 함께 GNU awk를 사용하는 것입니다 . 더 긴 숫자를 처리할 수 있습니다. 얼마나 오래 걸리는지는 확인하지 않았지만 한도가 꽤 높다고 확신합니다. :-) awk는 이 옵션을 포함하여 컴파일해야 합니다( awk 'BEGIN{ print( PROCINFO["gmp_version"], PROCINFO["prec_max"]) }'
다음으로 확인하세요).
awk -MF'|' '{ x=$2; grp_rem="";
while(x>0){
rem=x%62;
x=int(x/62);
grp_rem=rem" "grp_rem
}
printf("%-22s|%s\n",$0,grp_rem)
}
' <base62_while.txt >>base62_while.out
답변4
그리고 dc
:
sed 's/.*|\(.*\)/[&|]P\1p/;1s/^/62o/' base62_while.txt | dc > base62_while.out
또는 bc
( 의 역사적 구현은 bc
실제로 의 래퍼라는 점에 유의하십시오 dc
):
sed 's/.*|\(.*\)/"&|";\1/;1s/^/obase=62;/' base62_while.txt | bc > base62_while.out
주의해서 dc
긴 bc
출력 줄을 감싸십시오. GNU 구현을 사용하면 이러한 상황을 방지하기 위해 DC_LINE_LENGTH
및 BC_LINE_LENGTH
환경 변수를 0으로 설정할 수 있습니다.
$ echo '1|167883826163764944817996215305490271305728' | sed 's/.*|\(.*\)/[&|]P\1p/;1s/^/62o/' | dc
1|167883826163764944817996215305490271305728| 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00\
00
$ echo '1|167883826163764944817996215305490271305728' | sed 's/.*|\(.*\)/[&|]P\1p/;1s/^/62o/' | DC_LINE_LENGTH=0 dc
1|167883826163764944817996215305490271305728| 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00