.csv
다음과 같은 파일이 있습니다 .
IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP$DOLAP,200000000$2048000,400000000$2048000,200000000,400000000,5,5
$
기호 앞 부분은 원래 줄에 남아 있고 뒤 부분은 파일의 다른 필드가 에서와 동일한 값을 유지하는 바로 아래에 새로 생성된 줄로 전송되도록 기호가 포함된 모든 필드를 분할하고 싶습니다. 구분 문자가 처음 발견된 줄입니다. 행의 여러 필드에 분할 구분 기호가 포함된 경우 모든 필드의 "두 번째" 부분을 새로 생성된 동일한 행으로 전송합니다.
위의 예에서 출력은 다음과 같아야 합니다.
IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP,200000000,400000000,200000000,400000000,5,5
NAN,NAN,2,,,0,,0,,,,DOLAP,2048000,2048000,200000000,400000000,5,5
답변1
@Paul_Pedant가 언급한 요점은 실제로 오타이며 필드 OLAP$DOLAP
도 분할될 것이라고 가정합니다. 이 경우 다음 awk
절차(라고 함 splitfields.awk
)가 작동할 수 있습니다.
#/usr/bin/awk -f
{
copy=0;
for (i=1;i<=NF;i++)
{
j=index($i,"$");
if (j>0)
{
fields[i]=substr($i,j+1);
$i=substr($i,1,j-1);
copy=1
}
else fields[i]=$i;
}
print;
if (copy==1)
{
for (i=1;i<NF;i++) printf("%s%s",fields[i],OFS);
printf("%s%s",fields[NF],ORS)
}
}
전화주시면 이용 가능해요
user@host~$ awk -F, -v OFS="," -f splitfields.awk input.csv
스크립트는 각 필드에 기호가 있는지 확인 하고 추가 사용을 위해 $
필드를 배열로 복사합니다 . 발견 fields
되면 $
해당 필드현재의라인이 부품으로 축소됨앞으로배열 $
의 해당 항목이 fields
채워지면뒤쪽에이것 $
.
이 확인을 수행한 후에는 (수정될 수 있는) 현재 행이 어쨌든 인쇄됩니다. 또한 필드에 이 기호가 포함되어 있으면 $
배열 내용으로 구성된 새 줄이 CSV 형식으로 인쇄됩니다.fields
답변2
$ cat tst.awk
BEGIN { FS=OFS="," }
{
delete subFlds
numSubFlds = 0
for (i=1; i<=NF; i++) {
n = split($i,parts,/[$]/)
for (subFldNr=1; subFldNr<=n; subFldNr++) {
subFlds[i,subFldNr] = parts[subFldNr]
}
numSubFlds = (numSubFlds > n ? numSubFlds : n)
}
delete prev
for (subFldNr=1; subFldNr<=numSubFlds; subFldNr++) {
for (i=1; i<=NF; i++) {
curr = ( (i,subFldNr) in subFlds ? subFlds[i,subFldNr] : prev[i] )
printf "%s%s", curr, (i<NF ? OFS : ORS)
prev[i] = curr
}
}
}
.
$ awk -f tst.awk file
IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP,200000000,400000000,200000000,400000000,5,5
NAN,NAN,2,,,0,,0,,,,DOLAP,2048000,2048000,200000000,400000000,5,5
답변3
awk -F, -v OFS=, '{split("",q);for(i=j=1;i<=NF;i++){if(split($i,a,/\$/)>1){j++;$i=a[1];q[i]=a[2]}}print;if(j>1){for(i in q)$i=q[i];print}}' file
또는 확장하여 다음을 수행합니다.
awk -F, -v OFS=, '{
split("", q) # clear the q array; delete q is non-standard
for(i = j = 1; i <= NF; i++){
if(split($i, a, /\$/) > 1){ # if the field contains a $
j++ # increase the cnt of fields with a $
$i = a[1] # set the field to the part before the $
q[i] = a[2] # save the part after the $ in the q array
}
}
print # print the line with the parts before $
if(j > 1){ # if any field had a $
for(i in q) # for each field which had a $
$i = q[i] # replace it with the part after $
print # re-print the line with the parts after $
}
}' file
답변4
내가 올바르게 이해한 경우 일부 필드는 "이중" 변형 필드로 구분됩니다 $
. 해당 행의 사본 두 개만 있으면 됩니다. 여기서 첫 번째 행에는 첫 번째 변형이 포함되고 두 번째 행에는 두 번째 변형이 포함됩니다.
awk '{v1=$0; gsub(/\$[^,]+/,""); gsub (/,[^,]+\$/,",",v1); print $0; if (v1!=$0) print v1}' file1
IMSI,MSISDN,SUBCATEGY,EPCMMEHOST,EPCMMEREALM,EPCROAMSCH,PSROAMSCH,OINR,MSCNUMBER,VLRNUMBER,SGSNNUMBER,EPCAPNNAME,EPCAPNAMBRUP,EPCAPNAMBRDOWN,EPCAMBRUP,EPCAMBRDOWN,CHARGE,EPCCHARGCHRT
NAN,NAN,2,,,0,,0,,,,OLAP,200000000,400000000,200000000,400000000,5,5
NAN,NAN,2,,,0,,0,,,,DOLAP,2048000,2048000,200000000,400000000,5,5