bash 계산 스크립트, 오름차순으로 계산하는 것은 괜찮지만 내림차순으로 계산하는 것은 잘못되었습니다.

bash 계산 스크립트, 오름차순으로 계산하는 것은 괜찮지만 내림차순으로 계산하는 것은 잘못되었습니다.

다음 bash 스크립트는 1..1000의 높은 개수 범위에서 작동합니다.

카운트 범위가 1..1000000보다 높기 때문에 시작하는 데 시간이 걸립니다. 전반적으로 잘 작동합니다.

for i in {1..10}; do
    printf '\r%2d' $i
    sleep 1
done
printf '\n'

99..1부터 시작하는 숫자 범위의 역수에 대해서는 잘 작동합니다.

99 이상에서 시작하는 숫자 범위를 카운트다운하기 위해 pe 100..1 출력은 0이 포함된 숫자를 너무 많이 인쇄합니다. 이것을 어떻게 피할 수 있습니까?

답변1

귀하의 질문:

  1. 명령을 시작하는 데 시간이 좀 걸립니다. 이는 루프에 사용한 버팀대 확장 때문입니다. 확장이 먼저 이루어져야 합니다.확장하다, 이는 쉘이 반복할 범위의 모든 숫자를 포함하는 목록을 생성해야 함을 의미합니다. 이를 위해서는 시간(목록 생성)과 메모리(목록 저장)가 필요합니다. 내 컴퓨터에서 bash프로세스가 성장하는 것을 볼 수 있습니다.약 1400KiB에서 256MiB까지내가 목록을 생성하도록 요청할 때 {1..1000000}.

    대신, 산술 루프를 사용하는 것을 고려해 보세요.

    for (( i=1000000; i >= 1; --i )); do ...; done
    

    또는 POSIX 호환 루프,

    i=1000000
    while [ "$i" -ge 1 ]; do ...; i=$(( i - 1 )); done
    

    두 방법 모두 정적 숫자 목록을 반복하지 않고 대신 테스트 값을 기반으로 루프 본문을 실행한 다음 테스트가 성공하면 $i각 반복에서 변수 값을 감소시킵니다.1i

  2. 각 숫자 끝에는 "추가 0"이 있습니다. 캐리지 리턴 문자를 출력하여 커서를 줄의 시작 부분으로 다시 이동시키기 때문입니다. 커서는 이동하지만 줄은 지워지지 않으므로 새 숫자의 자릿수가 더 적더라도 마지막 출력 숫자의 끝은 계속 표시됩니다.

    이 문제를 해결하려면 다음을 사용해 보십시오.VT100 이스케이프 코드\e[2K커서를 줄의 시작 부분( )으로 이동하기 전에 전체 줄을 지우는 데 사용됩니다.

    for (( i=1000000; i >= 1; --i )); do
        printf '\e[2K\r%d' "$i"
        sleep 1
    done
    printf '\n'
    

    \e[1K커서 왼쪽의 줄 영역을 지우는 것처럼 작동합니다. 또는 \r%d\e[0K명확한 선을 사용하십시오옳은숫자 출력 후 커서의 위치입니다.

답변2

당신이 보는 문제는 먼저 쓴 100다음 같은 위치에서 시작하지만 출력 형식에 두 자리만 지정한다는 것 99입니다 .1%2d

지우기 지침을 제공하지 않았으므로 이것이 표시됩니다. 하지만 모두 한 줄에 있습니다.

What       # What
you        # was
see        # output


100        # 100
990        # 99
980        # 98
...
 90        # 9
 80        # 8
...
 10        # 1

세 자리 숫자로 형식을 지정하거나 공백 접미사를 추가해야 합니다.

printf "\r%3d" $i     # One option
printf "\r%2d " $i    # Another option

답변3

한 문자열을 다른 문자열로 바꾸려면 두 문자열이 모두 동일한 크기(또는 인쇄할 수 없는 문자(공백?)가 더 길어야 함)가 필요합니다.

123인쇄된 내용을 로 바꾸면 처음에 인쇄하는지 아니면 끝에서 인쇄하는지에 따라 또는 을 7얻게 됩니다 .723127

이를 수행하려면(동일한 크기의 문자열) 다음 중 하나를 수행할 수 있습니다.

  • 안정적인 크기의 버팀대 확장을 사용합니다.{000..123}
  • 전체 공간을 채우려면 printf를 사용하십시오.printf '\r%5s' "$i"
  • 긴 공백 문자열을 인쇄합니다.printf '\r%s ' "$i"
  • 줄이 끝날 때까지 줄을 지웁니다.printf '\r%s\e[K' "$i"
  • 전체 줄을 지우고 값을 인쇄합니다.printf '\e[2K\r%s' "$i"

그러나 {1..1000000}을 사용하는 것은 메모리에 저장하고 공백으로 나눈 다음 루프에서 사용해야 하는 긴 숫자 문자열을 생성하기 때문에 최상의 솔루션이 아닙니다. Bash의 더 나은 솔루션은 다음과 같습니다.

for(( i=1; i<1000; i++ )); do
    printf '\r%5d' $i
    sleep 0.01
done
echo

관련 정보