GNU seq(1)을 위한 휴대용 POSIX 쉘 대체?

GNU seq(1)을 위한 휴대용 POSIX 쉘 대체?

seq(1)나는 이것이 GNU 이외의 다른 시스템에서는 작동할 것이라고 기대할 수 없다는 것을 알았습니다 . seq(1)POSIX(bash 아님) 쉘에서 작성할 수 있는 간단한 재구현은 무엇입니까?

편집: 적어도 다양한 BSD, Solaris 및 Mac OS X에서 이것을 사용할 계획입니다.

답변1

대안 awkbc:

seq() (first=$1 incr=$2 last=$3
  echo "for (i = $first; i <= $last; i+=$incr) i" | bc -l
)

한 가지 장점은 CPU 이중의 크기/해상도에 의해 제한되지 않는다는 것입니다.

$ seq '(2^200)' '(2^100)' '(2^200+2^102)'
1606938044258990275541962092341162602522202993782792835301376
1606938044258990275541962092342430253122431223184289538506752
1606938044258990275541962092343697903722659452585786241712128
1606938044258990275541962092344965554322887681987282944917504
1606938044258990275541962092346233204923115911388779648122880

하지만 숫자가 너무 크면 줄 바꿈에 주의하세요.

$ seq '(2^500)' '(2^100)' '(2^500+2^101)'
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071009217256545885393\
053328527589376
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071010484907146113622\
454825230794752
32733906078961418700131896968275991522166420460430647894832913680961\
33796404674554883270092325904157150886684127560071011752557746341851\
856321934000128

답변2

공개그룹에 따르면POSIX awk 지원BEGIN, 그래서 다음과 같이 할 수 있습니다 awk:

awk -v MYEND=6 'BEGIN { for(i=1;i<=MYEND;i++) print i }'

이는 -v MYEND=6첫 번째 매개변수의 할당을 나타냅니다 seq. 즉, 다음과 같이 작동합니다.

seq() {
    end=$1
    awk -v end=$end 'BEGIN { for( i = 1; i <= end; i++) print i }'
}

또는 세 가지 변수인 start, increment 및 end를 사용할 수도 있습니다. (이것은 음수 증가나 부동 소수점을 지원하지 않습니다):

seq() { 
    if [ "$#" = 1 ]; then
        start=1 incr=1 end=$1
    elif [ "$#" = 2 ]; then
        start=$1 incr=1 end=$2
    elif [ "$#" = 3 ]; then
        start=$1 incr=$2 end=$3
    else 
        echo "error: invalid number of arguments" >&2
        return 1
    fi
    if ! [ "$incr" -ge 1 ]; then
        echo "error: invalid increment (must be >= 1)" >&2
        return 1
    fi
    awk -v start=$start -v incr=$incr -v end=$end '
        BEGIN {  for( i = start; i <= end; i += incr) print i }'
}

추가의솔라리스참고: Solaris에서는 /usr/bin/awk다음과 같습니다.아니요POSIX와 호환되려면 Solaris에서 nawk또는 를 사용해야 합니다 /usr/xpg4/bin/awk.

/usr/xpg4/binSolaris에서 POSIX 호환 스크립트를 실행하는 경우 PATH를 초기에 설정해야 할 수도 있습니다.

참고 답변:

답변3

whilePOSIX입니다

i=1
while [ "$i" -ne 11 ]
do    
    echo $i
    i=$(( $i + 1 ))
done

while휴대 가능하고 다재다능하며 활용도가 낮은 경우가 많습니다.

답변4

제가 생각할 수 있는 가장 짧고(기본 목표) 가장 저렴한(소비된 시스템 리소스 측면에서 - 보조 목표) 변형은 다음과 같습니다.

while :; do echo x; done | sed 10q

"10"을 원하는 반복 횟수로 바꿉니다.

다음과 같이 "for" 루프에서 사용할 수 있습니다.

for i in `while :; do echo x; done | sed 10q`; do echo hello; done

그러나 "while" 루프에서는 더 효율적으로 사용할 수 있습니다.

while :; do echo x; done | sed 10q | while read x; do echo hello; done

이렇게 하면 단일 프로세스 호출과 잠재적으로 많은 수의 "x" 문자를 "for" 인수로 임시 저장하는 것을 방지할 수 있습니다.

제가 생각하는 가장 효율적인 방법은

i=10; while case $i in 0) break; esac; do i=$(($i - 1)); echo hello; done

"echo" 이외의 쉘 내장 기능만 사용하며 다른 프로세스 호출은 필요하지 않습니다. 불행히도 대본에서 보는 것은 꽤 추악하고 불쾌합니다. 그러나 스크립트 성능이 중요하다면 이것이 제가 생각할 수 있는 최고의 이식 가능한 솔루션입니다.

물론 awk와 bc도 해당 작업을 수행할 수 있습니다. 그러나 둘 다 작업에 필요한 것보다 훨씬 더 강력한 유틸리티이므로 이러한 간단한 작업에 사용하는 것은 나에게 시스템 리소스 낭비처럼 보입니다.

관련 정보