source

모든 것이 같은 폭을 갖도록 bash에서 정수 시퀀스를 제로 패드하는 방법은 무엇입니까?

ittop 2023. 5. 22. 21:39
반응형

모든 것이 같은 폭을 갖도록 bash에서 정수 시퀀스를 제로 패드하는 방법은 무엇입니까?

몇 가지 가치관을 반복해야 합니다.

for i in $(seq $first $last)
do
    does something here
done

위해서$first그리고.$last저는 그것의 길이가 고정된 길이 5로 해주세요.그래서 만약 입력이1앞에 0을 더해서 0이 되도록 해야 합니다.00001까지 순환합니다.99999예를 들어, 길이는 5여야 합니다.

예:00002,00042,00212,12312등등.

어떻게 해야 할지 생각나는 거 있어요?

구체적인 경우에는 사용하는 것이 아마도 가장 쉬울 것입니다.-f에 깃발을 내미는.seq목록을 출력할 때 번호 형식을 지정할 수 있습니다.예:

for i in $(seq -f "%05g" 10 15)
do
  echo $i
done

는 다음과 같은 출력을 생성합니다.

00010
00011
00012
00013
00014
00015

더 일반적으로 말하면,bash가지다printf다음과 같이 0으로 출력을 패딩할 수 있습니다.

$ i=99
$ printf "%05d\n" $i
00099

사용할 수 있습니다.-v플래그 - 출력을 다른 변수에 저장합니다.

$ i=99
$ printf -v j "%05d" $i
$ echo $j
00099

주의:printf에 약간 다른 형식을 지원합니다.seq그래서 당신은 사용할 필요가 있습니다.%05d대신에%05g.

더 쉬워도 그냥 할 수 있습니다.

for i in {00001..99999}; do
  echo $i
done

시퀀스의 끝에 최대 패딩 길이가 있는 경우(예: 5자리 숫자를 원하는 경우), 명령어는seq 1 10000), 사용할 수 있는 것보다 많습니다.-wseq 플래그 - 패딩 자체를 추가합니다.

seq -w 1 10

을 생산할 것입니다.

01
02
03
04
05
06
07
08
09
10

예를 들어 "%05d"와 함께 printf를 사용합니다.

printf "%05d" 1

매우 단순한 사용printf

[jaypal:~/Temp] printf "%05d\n" 1
00001
[jaypal:~/Temp] printf "%05d\n" 2
00002

다음과 같이 awk를 사용합니다.

awk -v start=1 -v end=10 'BEGIN{for (i=start; i<=end; i++) printf("%05d\n", i)}'

출력:

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

업데이트:

순수 bash 대체 방법으로 동일한 출력을 얻기 위해 다음을 수행할 수 있습니다.

for i in {1..10}
do
   printf "%05d\n" $i
done

이렇게 하면 외부 프로그램 사용을 피할 수 있습니다.seq일부 *nix 버전에서는 사용할 수 없습니다.

필요한 숫자보다 더 많은 숫자(0)로 출력을 입력한 다음 테일을 사용하여 원하는 숫자만 사용합니다.마지막 다섯 자리를 얻으려면 꼬리에 '6'을 사용해야 합니다 :)

for i in $(seq 1 10)
do
RESULT=$(echo 00000$i | tail -c 6)
echo $RESULT
done

N자리를 원하는 경우 10^N을 추가하고 첫 번째 자리를 삭제합니다.

for (( num=100; num<=105; num++ ))
do
  echo ${num:1:3}
done

출력:

01
02
03
04
05

다른 방법:

zeroos="000"
echo 

for num in {99..105};do
 echo ${zeroos:${#num}:${#zeroos}}${num}
done

따라서 임의의 숫자를 변환하는 간단한 함수는 다음과 같습니다.

function leading_zero(){

    local num=$1
    local zeroos=00000
    echo ${zeroos:${#num}:${#zeroos}}${num} 

}

외부 프로세스 포킹을 사용하지 않는 한 가지 방법은 문자열 조작이며, 일반적인 경우 다음과 같습니다.

#start value
CNT=1

for [whatever iterative loop, seq, cat, find...];do
   # number of 0s is at least the amount of decimals needed, simple concatenation
   TEMP="000000$CNT"
   # for example 6 digits zero padded, get the last 6 character of the string
   echo ${TEMP:(-6)}
   # increment, if the for loop doesn't provide the number directly
   TEMP=$(( TEMP + 1 ))
done

이것은 WSL에서도 꽤 잘 작동하는데, 여기서 포킹은 정말로 무거운 작업입니다.1,10000개의 파일 목록을 가지고 있었습니다.printf "%06d" $NUM1분 이상 걸렸고, 상기 솔루션은 약 1초 만에 실행되었습니다.

이 기능은 다음과 같습니다.

for i in {0..9}{0..9}{0..9}{0..9}
do
  echo "$i"
done

고정 길이를 달성하기 위해 숫자를 0으로 채우는 경우에는 가장 가까운 10 eg의 배수를 추가하면 됩니다.두 자리의 경우 10^2를 추가한 다음 출력을 표시하기 전에 첫 번째 1을 제거합니다.

이 솔루션은 for 루프를 사용하여 임의의 길이의 단일 숫자 또는 전체 숫자 시퀀스를 패딩/포맷할 수 있습니다.

# Padding 0s zeros:
# Pure bash without externals eg. awk, sed, seq, head, tail etc.
# works with echo, no need for printf

pad=100000      ;# 5 digit fixed

for i in {0..99999}; do ((j=pad+i))
    echo ${j#?}
done

Mac OS X 10.6.8, Bash 버전 3.2.48에서 테스트됨

TL;DR

$ seq 1 10 | awk '{printf("%05d\n", $1)}'

입력(패턴 1).느림):

$ seq 1 10 | xargs -n 1 printf "%05d\n"

입력(패턴 2).빠름):

$ seq 1 10 | awk '{printf("%05d\n", $1)}'

출력(각 사례에서 동일한 결과):

00001
00002
00003
00004
00005
00006
00007
00008
00009
00010

설명.

저는 위의 패턴을 제안하고 싶습니다.이러한 구현을 명령어로 사용하여 쉽게 다시 사용할 수 있습니다.이러한 명령에서 주의해야 할 것은 변환된 후의 숫자의 길이입니다.(숫자를 바꾸는 것처럼)%05d안으로%09d할 수 .) 또한 다음과 같은 다른 솔루션에도 적용할 수 있습니다.예제는 내 환경에 너무 의존적이어서 출력이 다를 수 있지만 유용성은 쉽게 알 수 있다고 생각합니다.

$ wc -l * | awk '{printf("%05d\n", $1)}'
00007
00001
00001
00001
00013
00017
00001
00001
00001
00043

그리고 이런 식으로:

$ wc -l * | awk '{printf("%05d\n", $1)}' | sort | uniq
00001
00007
00013
00017
00043

게다가, 당신이 이런 식으로 글을 쓴다면, 우리는 또한 비동기식으로 명령을 실행할 수 있습니다. (좋은 기사입니다.

고지 사항:저는 이것에 대해 확신할 수 없고 *nix 전문가도 아닙니다.

성능 테스트:

매우 느림:

$ time seq 1 1000 | xargs -n 1 printf "%09d\n" > test
seq 1 1000  0.00s user 0.00s system 48% cpu 0.008 total
xargs -n 1 printf "%09d\n" > test  1.14s user 2.17s system 84% cpu 3.929 total

비교적 빠른 속도:

for i in {1..1000}
do
   printf "%09d\n" $i
done
$ time sh k.sh > test
sh k.sh > test  0.01s user 0.01s system 74% cpu 0.021 total


for i in {1..1000000}
do
   printf "%09d\n" $i
done
$ time sh k.sh > test
sh k.sh > test  7.10s user 1.52s system 99% cpu 8.669 total

빠른 속도:

$ time seq 1 1000 | awk '{printf("%09d\n", $1)}' > test
seq 1 1000  0.00s user 0.00s system 47% cpu 0.008 total
awk '{printf("%09d\n", $1)}' > test  0.00s user 0.00s system 52% cpu 0.009 total


$ time seq 1 1000000 | awk '{printf("%09d\n", $1)}' > test
seq 1 1000000  0.27s user 0.00s system 28% cpu 0.927 total
awk '{printf("%09d\n", $1)}' > test  0.92s user 0.01s system 99% cpu 0.937 total

고성능 솔루션을 구현해야 하는 경우 셸 스크립트를 사용하지 않고 다른 기술이 필요할 수 있습니다.

조합seq -w질문에 대한 @precipee의 의견으로 답변하면 다음을 수행할 수 있습니다.

seq -w 1 1000 | while read -r i; do
    echo $i
done

@tripleee linked 기사에서 설명한 것처럼, 이것은 전체 시퀀스를 한 번에 메모리에 로드하는 대신 파이프에서 한 번에 단일 숫자를 읽습니다.

버전이나 루프 버전에 비해 의미 {0000..1000}판본

루프를 피할 수 있습니까?

여러 인수를 허용하는 명령을 실행하기 위해 이 작업을 수행하는 경우 루프 작업보다 여러 인수를 사용하여 명령을 직접 실행하고 확장을 지원하는 것이 더 빠를 수 있습니다.

예를 들어 시스템에서 다음 루프를 실행하는 데 7초가 걸립니다.

for i in {0001..9001}; do; touch $i; done

그러나 다음은 거의 즉시 실행됩니다.

touch {0001..9001}

1.) 1부터 1000까지의 일련의 숫자 'seq'를 만들고 너비 '-w'를 고정합니다(이 경우 너비는 끝 숫자의 길이로 결정됩니다. 이 경우 1000에 대한 4자리 숫자).

2.) 또한 'sed -n'을 사용하여 원하는 숫자를 선택합니다(이 경우 1-100번을 선택합니다).

3.) 각 숫자를 '표기'합니다.숫자는 변수 'i'에 저장되며, '$'를 사용하여 액세스합니다.

찬성: 이 코드는 꽤 깨끗합니다.

단점: 'seq'가 모든 Linux 시스템에 기본적인 것은 아닙니다(제가 알기로는).

for i in `seq -w 1 1000 | sed -n '1,100p'`; 
do 
    echo $i; 
done

필없니다가 필요 없습니다.awk - 위해면니 --아을것그▁that.seq또는jot단독으로 충분합니다.

% seq -f '%05.f' 6     # bsd-seq
00001
00002
00003
00004
00005
00006

% gseq -f '%05.f' 6    # gnu-seq
00001
00002
00003
00004
00005
00006

% jot -w '%05.f' 6
00001
00002
00003
00004
00005
00006

당신이 큰 영토로 들어가지 않는 한:

% gawk -Mbe '

  function __(_,___) {
      return +_<+___?___:_
  }
  BEGIN {
        _+=_^=_<_                 
      ____="%0*.f\n"   
  } {                      
       ___=__($--_, !+$++_)                
     _____=__(++_+--_, length(______=+$NF)) 
     do {                     
        printf(____,_____,___)
     }  while (___++<______) 
                                                       
  }' <<< '999999999999999999996 1000000000000000000003'

0999999999999999999996
0999999999999999999997
0999999999999999999998
0999999999999999999999
1000000000000000000000
1000000000000000000001
1000000000000000000002
1000000000000000000003

——————————————————————————————————————————————————

만약 당신이 엄청난 범위의 숫자를 출력해야 한다면, 이 접근법은 조금 더 빠를 수도 있습니다.

  • 단위로 , 쪽-0-0-0-0-0-9-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-00.049s

  • *caveat : 모든 입력 범위를 커버할 여유가 없었습니다 :: 10의 거듭제곱을 수용하는 개념 증명일 뿐입니다.

——————————————————————————————————————————————————

 ( time ( LC_ALL=C mawk2 '
 
   function jot(____,_______,_____,_,__,___,______) {
       if(____==(____^!____)) {
           return +____<+_______\
               ? sprintf("%0*.f",_______,____)\
               : +____ 
        }
        _______= (_______-=____=length(____)-\
                 (_=!(_<_)))<+_ \
                 ? "" \
                 : sprintf("%0*.f",_______,!_)
           __=_= (!(__=_+=_+_))(__=(-+--_)+(__+=_)^++_)\
                 (__+=_=(((_--^_--+_++)^++_-_^!_)/_))(__+_)
          _____= "."
     gsub(_____,"\\&&",__)
     ____—-
     do { 
         gsub(_____,__,_)
        _____=_____"." 
     } while(—____)

     gsub(_____,(_______)"&\n",_)
     sub("^[^\n]+[\n]","",_)
     sub(".$",""~"",_______)
     
     return \
     (_)(_______)\
     sprintf("%0*.f",length(_____),__<__)

   } { print jot($1,$2) }' <<< '10000000 9'
  
 ) | pvE9 ) |xxh128sum |ggXy3 | lgp3

 sleep 2
 ( time ( LC_ALL=C jot 1000000 | 
          LC_ALL=C mawk2 '{ printf("%09.f\n", $1) }' 
 
 ) | pvE9 ) |xxh128sum |ggXy3 | lgp3


     out9: 9.54MiB 0:00:00 [ 275MiB/s] [ 275MiB/s] [<=> ]
( LC_ALL=C mawk2  <<< '1000000 9'; )

0.04s user 0.01s system 93% cpu 0.049 total

e0491043bdb4c8bc16769072f3b71f98  stdin


     out9: 9.54MiB 0:00:00 [36.5MiB/s] [36.5MiB/s] [  <=> ]
( LC_ALL=C jot 1000000 | LC_ALL=C mawk2 '{printf("%09.f\n", $1)}'; )

0.43s user 0.01s system 158% cpu 0.275 total

e0491043bdb4c8bc16769072f3b71f98  stdin

천만 번을 할 때쯤이면 시차가 눈에 띕니다.

 out9: 95.4MiB 0:00:00 [ 216MiB/s] [ 216MiB/s] [<=> ]
 ( LC_ALL=C mawk2  <<< '10000000 9'; )

 0.38s user 0.06s system 95% cpu 0.458 total

 be3ed6c8e9ee947e5ba4ce51af753663  stdin


 out9: 95.4MiB 0:00:02 [36.3MiB/s] [36.3MiB/s] [ <=> ]
 ( LC_ALL=C jot 10000000 | LC_ALL=C mawk2 '{printf("%09.f\n", $1)}'; )

 4.30s user 0.04s system 164% cpu 2.638 total
 
 be3ed6c8e9ee947e5ba4ce51af753663  stdin




 out9: 95.4MiB 0:00:02 [35.2MiB/s] [35.2MiB/s] [ <=> ]

 ( LC_ALL=C python3 -c '__=1; ___=10**7;

   [ print("{0:09d}".format(_)) for _ in range(__,___+__) ]' 

 ) | pvE9 ) | xxh128sum |ggXy3 | lgp3 ;  )

 2.68s user 0.04s system 99% cpu 2.725 total
 
 be3ed6c8e9ee947e5ba4ce51af753663  stdin

언급URL : https://stackoverflow.com/questions/8789729/how-to-zero-pad-a-sequence-of-integers-in-bash-so-that-all-have-the-same-width

반응형