sed 특수 문자 교체 챌린지

sed 특수 문자 교체 챌린지

sed를 사용하여 TB를 GB로 변환하려고 합니다. TB가 있는 필드는 한 자리 숫자(2T, 8T)이거나 여러 자리 숫자(2.001T, 1.501T)입니다. 교체품이 제대로 작동하고 있다고 생각했는데 오류가 발생하여 이해할 수 없는 것 같습니다.

파일 샘플:

ftwepsiprdsql02,ftwepsiprdsql02_F,2.001T,1.680T
ftwepsiprdsql02,ftwepsiprdsql02_G,801G,176.786G
ftwepsiprdsql02,ftwepsiprdsql02_H,501G,6.565G
ftwepsiprdsql02,ftwepsiprdsql02_I,1.001T,539.504G
ftwepsiprdsql02,ftwepsiprdsql02_J,501G,478.211G
ftwepsiprdsql02,ftwepsiprdsql02_X,1.501T,68.021G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun248,8T,4.450T
rxi0738_foc_cl1,rxi0738_foc_cl1_lun250,8T,5.857T
rxi0738_foc_cl1,rxi0738_foc_cl1_lun252,8T,4.681T
rxi0738_foc_cl1,rxi0738_foc_cl1_lun254,8T,4.657T

세 번째와 네 번째 필드(할당/사용된 용량)를 각각 바꿀 예정입니다. 초기 접근 방식은 한 자리 용량 숫자를 여러 자리 숫자(2.000T, 8.000T)와 일치하도록 변경하는 것이었습니다.

세 번째 필드의 한 자리 코드를 바꾸십시오.

for i in `awk -F , '{print $3}' $TMPRPT| grep \[0-9\]T | grep -v "\." `
do
TVAL=$(echo $i | sed 's/T/.000T/')
sed -i .tmp "s/$i/$TVAL/" "$TMPRPT"
done

이론적으로 이는 모든 한 자리 숫자를 여러 자리 숫자와 일치하도록 변경해야 하므로 TB에서 GB로의 최종 변환은 간단합니다. awk 명령은 완벽하게 실행되어 나에게오직한 자리 출력이지만 일단 for 루프에 넣고 sed -i 명령을 실행하면 교체가 수행됩니다.모두여러 자리 숫자를 포함하여 T 이름이 있는 필드:

ftwepsiprdsql02,ftwepsiprdsql02_F,2.001.000T,1.680T
ftwepsiprdsql02,ftwepsiprdsql02_G,801G,176.786G
ftwepsiprdsql02,ftwepsiprdsql02_H,501G,6.565G
ftwepsiprdsql02,ftwepsiprdsql02_I,1.001.000T,539.246G
ftwepsiprdsql02,ftwepsiprdsql02_J,501G,478.211G
ftwepsiprdsql02,ftwepsiprdsql02_X,1.501.000T,68.021G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun248,8.000T,4.450T
rxi0738_foc_cl1,rxi0738_foc_cl1_lun250,8.000T,5.857T
rxi0738_foc_cl1,rxi0738_foc_cl1_lun252,8.000T,4.681.000T
rxi0738_foc_cl1,rxi0738_foc_cl1_lun254,8.000T,4.657T

이 작업을 수행하는 더 쉬운 방법이 있다는 것을 알고 있으므로 다른 대안도 열려 있지만 sed -i가 원하는 방식으로 작동하도록 만드는 방법도 알고 싶습니다.

(플랫폼은 Linux 커널의 축소 버전을 실행하는 Isilon입니다. 대부분의 명령을 사용할 수 있지만 전부는 아닙니다.)

답변1

GNU Coreutils가 있는 경우 numfmt:

$ numfmt -d, --field=3,4 --from=auto --round=nearest < file | 
    numfmt -d, --field=3,4 --to-unit=G --suffix=G
ftwepsiprdsql02,ftwepsiprdsql02_F,2001G,1680G
ftwepsiprdsql02,ftwepsiprdsql02_G,801G,177G
ftwepsiprdsql02,ftwepsiprdsql02_H,501G,7G
ftwepsiprdsql02,ftwepsiprdsql02_I,1001G,540G
ftwepsiprdsql02,ftwepsiprdsql02_J,501G,479G
ftwepsiprdsql02,ftwepsiprdsql02_X,1501G,69G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun248,8000G,4450G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun250,8000G,5857G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun252,8000G,4681G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun254,8000G,4657G

또는 Perl을 사용하여:

perl -F, -pe '
  $_ = join ",", map { $_ =~ s/^(\d*(\.\d+)?)T$/sprintf "%.0fG", 1000*$1/e; $_ } @F
' file

답변2

1T=1000G로 가정합니다.

sed가 완료되었으므로 이론적으로 곱셈에 필요한 것보다 더 강력하지만 짧게 유지하고 루프를 사용하지 않고 간단한 텍스트 교체를 통해 변경했습니다.

필요한 변경 사항을 분석해 보겠습니다. T가 있지만 마침표는 없는 단일 필드를 ".000"이 있는 필드로 변경하는 것부터 시작하세요. 필드가 2개이므로 "g"가 필요합니다. 필드를 시작하기 위한 좋은 쉼표가 있으므로 이를 활용하십시오.

  s/\(,[0-9]*\)T/\1.000T/g

이제 소수점 이하 3자리가 없는 필드가 있는 경우를 대비하여 정리 작업을 수행합니다. 마침표 뒤에 아무것도 없으면 3개의 0을 추가하고, 1개의 숫자가 있으면 2개의 0을 추가하고, 2개의 숫자가 있으면 0을 추가하고 세 번째 숫자 뒤에 있는 추가 숫자를 제거합니다.

s/\(,[0-9]*\.\)T/\1000T/g
s/\(,[0-9]*\.[0-9]\)T/\100T/g
s/\(,[0-9]*\.[0-9][0-9]\)T/\10T/g
s/\(,[0-9]*\.[0-9][0-9][0-9]\)[0-9]*T/\1T/g

이제 T를 G로 변경하고 마침표를 제거합니다.

s/\(,[0-9]*\)\.\([0-9][0-9][0-9]\)T/\1\2G/g

이제 편의를 위해 앞에 오는 0을 제거하세요.

s/,0*\([1-9][0-9]*G\)/,\1/g

모든 명령을 종합하고 샘플 데이터 결과 제공

ftwepsiprdsql02,ftwepsiprdsql02_F,2001G,1680G
ftwepsiprdsql02,ftwepsiprdsql02_G,801G,176.786G
ftwepsiprdsql02,ftwepsiprdsql02_H,501G,6.565G
ftwepsiprdsql02,ftwepsiprdsql02_I,1001G,539.504G
ftwepsiprdsql02,ftwepsiprdsql02_J,501G,478.211G                                                                                                        
ftwepsiprdsql02,ftwepsiprdsql02_X,1501G,68.021G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun248,8000G,4450G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun250,8000G,5857G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun252,8000G,4681G
rxi0738_foc_cl1,rxi0738_foc_cl1_lun254,8000G,4657G

관련 정보