쉼표로 구분된 텍스트 파일에 문제가 있습니다. 혼합 레이아웃(수백 개)이 있는 파일 수신을 시작하려고 할 때 일부 레코드에는 7개의 필드(총 쉼표 6개)가 있는 반면 동일한 파일의 다른 레코드에는 6개의 필드(쉼표 5개)가 있습니다. 총).
5개의 쉼표가 포함된 레코드를 찾으면 레코드 끝에 쉼표를 추가하고 NA를 추가하여 로드 프로세스에서 마지막 NA인 7개의 필드가 있다고 생각하도록 하고 싶습니다.
이것이 내가 지금 가지고 있는 것입니다. 첫 번째 레코드에는 7개의 필드가 있고 두 번째 레코드에는 6개만 있습니다.
200000003183000100,Data,NA,0,IN,0,0.00
200000004625000000,Data,NA,0,IN,0
이것이 내가 예상한 것입니다(두 레코드 모두 7개의 필드를 가집니다).
200000003183000100,Data,NA,0,IN,0,0.00
200000004625000000,Data,NA,0,IN,0,NA
sed나 이와 유사한 것으로 쉼표를 세고 쉼표가 5개만 있을 때마다 파일 끝에 ,NA를 추가하면 됩니다. 이는 수백 개의 파일에서 발생하므로 파일 이름을 매개변수로 사용해야 하는지 또는 이와 유사한 것을 사용해야 하는지는 알 수 없습니다.
답변1
만약에앗허용된:
awk -F, 'NF==6{$0=$0",NA"}1' file
답변2
~처럼길 퀴노(Gil Quinault)의 답변, 그러나 현재 행 끝에 문자열 대신 새 필드로 새 필드를 추가합니다. 또한 명령줄에서 구분 기호 및 예상 필드 수를 구성할 수 있으며 누락된 필드는 문자열로 채워집니다 NA
.
$ awk -F , -v nf=7 'BEGIN { OFS = FS } { for (i = NF+1; i <= nf; ++i ) $i = "NA" }; 1' file
200000003183000100,Data,NA,0,IN,0,0.00
200000004625000000,Data,NA,0,IN,0,NA
$ awk -F , -v nf=12 'BEGIN { OFS = FS } { for (i = NF+1; i <= nf; ++i ) $i = "NA" }; 1' file
200000003183000100,Data,NA,0,IN,0,0.00,NA,NA,NA,NA,NA
200000004625000000,Data,NA,0,IN,0,NA,NA,NA,NA,NA,NA
이는 분명히 입력이 다음과 같다고 가정합니다.간단한 CSV형식(삽입된 쉼표나 줄 바꿈을 포함하지 않는 필드)
답변3
awk의 효율성을 높이기 위해 필요한 경우가 아니면 레코드( $0
)나 필드( $1
등) 를 수정하지 마세요. $2
이는 그 중 어떤 것도 수정하지 않습니다.
awk -F, '{print $0 (NF==6 ? ",NA" : "")}'
다른 기존 awk 답변은 $0을 수정하거나 필드를 수정하는데, 둘 다 처리 속도가 느려집니다.
이는 $0을 직접 변경합니다(따라서 간접적으로 필드를 추가함).
awk -F, 'NF==6{$0=$0",NA"}1'
awk '/(.*,){6}/ || sub(/$/,",NA")'
awk '!/(.*,){6}/{$0=$0",NA"}1'
이를 위해서는 awk가 크기가 증가함에 따라 이동할 새 메모리를 찾아야 하며 $0
(변수의 크기를 연결하거나 변경하는 것은 awk에서 가장 느린 작업 중 하나임) awk가 $0
필드로 다시 분할되도록 합니다.
이는 필드를 직접 변경합니다(따라서 $0 간접적으로).
awk -F, -v nf=7 'BEGIN { OFS = FS } (NF < nf){ $(nf)="N/A"}1'
awk -F, -v nf=7 'BEGIN { OFS = FS } { for (i = NF+1; i <= nf; ++i ) $i = "NA" }; 1'
이로 인해 awk가 해당 필드에서 다시 빌드되고 크기 증가로 인해 $0
이동할 새 메모리를 찾으려면 awk가 다시 필요합니다.$0
GNU awk를 사용하여 수백 개의(ARG_MAX 미만) CSV 파일에 대해 awk 스크립트를 실행하려면 다음을 수행하세요.
awk -i inplace 'script' file*.csv
또는 awk를 사용하십시오.
tmp=$(mktemp)
for file in file*.csv; do
awk 'script' "$file" > "$tmp" &&
mv -- "$tmp" "$file"
done
답변4
Posix sed
, 여섯 번째 쉼표를 변경하려고 시도하고, 성공하면 인쇄하고 다음 레코드를 읽기 위해 돌아갑니다(테스트 명령티) 그렇지 않으면 ,NA
현재 레코드의 끝에 문자열을 추가합니다.
sed '
s/,/,/6;t
s/$/,NA/
' file
을 사용하는 awk
한 가지 방법은 다음과 같습니다.
awk '/(.*,){6}/ || sub(/$/,",NA")' file
여러 파일에 대해 이 작업을 수행해야 하는 경우 명령을 사용하는 경우가 있습니다 find
.
CSV 파일의 이름이 지정되었다고 가정해 보겠습니다.*.csv
find . -type f -name '*.csv' -exec \
sed -i 's/,/,/6;t' -e 's/$/,NA' {} +
awk의 경우, awk가 지원한다면 inplace 옵션을 사용하세요(GNU awk 버전 4.1.0 이상)
find . -type f -name "*.csv" -exec \
awk -i inplace '!/(.*,){6}/{$0=$0",NA"}1' {} +
상징{} +여러 파일 이름을 awk 또는 sed 명령줄에 연결하여 이러한 유틸리티에 대한 호출을 최소화합니다.
노트:
- 파일에는 쉼표가 5개 또는 6개 있습니다.
- 필드 자체에는 쉼표를 포함할 수 없습니다.
- 줄 끝은 Linux 스타일입니다(\n).