csv 파일의 명령줄에서 개별적으로 실행할 때 완벽하게 작동하는 두 개의 sed 명령이 있습니다. 둘 다 csv 파일 열 중 하나의 소수점 형식을 수정하고 소수점 이하 자릿수를 두 자리로 반올림하도록 설계되었습니다.
- 소수점 이하 자릿수가 하나만 있는 숫자에 0을 추가합니다.
sed -r -e 's/[0-9]\;[0-9]+\.[0-9]/&0/'
- 소수점 이하 두 자리 이상의 반올림 숫자:
sed -re 's/([0-9]+\.[0-9]{2})[0-9]+/\1/'
이제 동시에 적용할 수 있도록 sed 스크립트에 넣고 싶습니다. 저는fixed_floats.sed라는 스크립트를 만들었습니다.
#!/bin/sed
s/[0-9]\;[0-9]+\.[0-9]/&0/
s/(\[0-9]+\.[0-9]{2}\)[0-9]+/\1/
다음 명령을 사용하여 실행하려고 하면:
sed -f fix_floats.sed titanic-passengers.csv
출력에서 아무 것도 변경되지 않는 것 같습니다. (sed 명령의 정규식이 확장되어 있으므로 작동하지 않는 이유는 스크립트를 실행할 때 지정하지 않았기 때문인 것 같습니다.)
다음 명령을 사용하여 실행하려고 하면:
sed -E -f fix_floats.sed titanic-passengers.csv
다음 오류가 발생합니다.
sed: file fix_floats.sed line 5: invalid reference \1 on `s' command's RHS
csv에 효율적으로 적용할 수 있도록 확장 정규식을 사용하여 sed 스크립트를 만드는 방법에 대한 제안 사항이 있습니까?
원시 출력: (관심 있는 열은 행 끝에서 세 번째 열입니다.)
356;No;3;Vanden Steen, Mr. Leo Peter;male;28.0;0;0;345783;9.5;;S
546;No;1;Nicholson, Mr. Arthur Ernest;male;64.0;0;0;693;26.0;;S
원하는 출력:
356;No;3;Vanden Steen, Mr. Leo Peter;male;28.0;0;0;345783;9.50;;S
546;No;1;Nicholson,Mr.Arthur Ernest;male;64.0;0;0;693;26.00;;S
답변1
스크립트의 마지막 줄은 명령줄에서 실행되는 스크립트와 다릅니다. 두 개의 백슬래시를 추가할 이유가 없습니다.
s/(\[0-9]+\.[0-9]{2}\)[0-9]+/\1/
~해야 한다
s/([0-9]+\.[0-9]{2})[0-9]+/\1/
(또한 첫 번째 명령에서 세미콜론을 이스케이프할 필요는 없지만 s///
그냥 무시되기 때문에 문제가 되지 않습니다.)
답변2
다음과 같이 부동 소수점 숫자의 형식을 지정할 수 있는 언어를 사용하는 것이 더 쉽습니다.
$ awk -F ';' 'BEGIN { OFS=FS } { $(NF-2) = sprintf("%.2f", $(NF-2)) }; 1' file
356;No;3;Vanden Steen, Mr. Leo Peter;male;28.0;0;0;345783;9.50;;S
546;No;1;Nicholson, Mr. Arthur Ernest;male;64.0;0;0;693;26.00;;S
프로그램 은 끝에서부터 시작하여 awk
세 번째 구분 필드를 소수점 이하 두 자리의 부동 소수점 숫자로 다시 작성합니다 . ;
이것은 반올림을 수행하므로 0.009
가 됩니다 0.01
. 잘라 내기 호출 대신에 사용합니다 int($(NF-2)*100)/100)
.$(NF-2)
sprintf()
표현 sed
에 백슬래시가 너무 많습니다. 특히 캡처링 그룹을 종료해야 하는 확장 정규식에서 which를 사용했고 \)
중요한 대괄호 표현식을 비활성화하기 위해 which를 사용했으며 대신 불필요한 부분을 사용했습니다.)
\[
[
\;
;
표준 sed
용어로 표현하면 다음과 같습니다.
s/\(\.[0-9]\)\(\(;[^;]*\)\{2\}\)$/\10\2/
s/\(\.[0-9][0-9]\)[0-9]\{1,\}\(\(;[^;]*\)\{2\}\)$/\1\2/
확장 정규식과 동일합니다(현재는 다음과 함께 사용하기 위한 비표준입니다 sed -E
.
s/(\.[0-9])((;[^;]*){2})$/\10\2/
s/(\.[0-9][0-9])[0-9]+((;[^;]*){2})$/\1\2/
이는 수정한 필드 뒤의 마지막 두 필드와 명시적으로 일치하므로 표현식보다 안전합니다. 따라서 실수로 임의의 부동 소수점 값을 수정할 위험이 적습니다.