Muhammad Abdul Rifqi
Muhammad Abdul Rifqi

Reputation: 47

Replace character or fixing incorrect new line character in csv using UNIX command

I have a Pipe-delimited CSV from a company report production. But there is a 'comment' field that the data inputted randomly by the employee and causes failed to load the data into database. How do i solve it using UNIX command or shell script?

The data sample is look like this :

Employee ID|Time Type|Start Date|End Date|Number Of Days|Comment|Approved
90006731|Leave|04/02/2019|04/02/2019|1|annual leaves|Y
90005267|Leave|04/02/2019|04/02/2019|1||Y
90007366|Leave|04/02/2019|04/02/2019|1|* Take care of vehicle taxes 
* Vehicle Repair 
* Community service
* Swimming|Y
90005052|Leave|04/02/2019|04/02/2019|1|Son's field trip|Y
90006253|Death of Wife/Husband/Child/Parent|04/01/2019|04/02/2019|2||Y
90007595|Leave|04/01/2019|04/01/2019|1|family plan|Y
90004064|Leave|08/18/2020|08/21/2020|3|Dear Mas Rama,
Please kindly approve, Mas Okto was oke.
Thanks.|Y
90007072|Sick Leave Without Certificate|04/01/2019|04/01/2019|1|Sick leave due to eye swelling|Y
90004371|Sick Leave|04/01/2019|04/05/2019|4||Y
90007431|Sick Leave|04/01/2019|04/01/2019|1||Y

Required Output :

Employee ID|Time Type|Start Date|End Date|Number Of Days|Comment|Approved
90006731|Leave|04/02/2019|04/02/2019|1|annual leaves|Y
90005267|Leave|04/02/2019|04/02/2019|1||Y
90007366|Leave|04/02/2019|04/02/2019|1|* Take care of vehicle taxes * Vehicle Repair * Community service * Swimming|Y
90005052|Leave|04/02/2019|04/02/2019|1|Son's field trip|Y
90006253|Death of Wife/Husband/Child/Parent|04/01/2019|04/02/2019|2||Y
90007595|Leave|04/01/2019|04/01/2019|1|family plan|Y
90004064|Leave|08/18/2020|08/21/2020|3|Dear Mas Rama, Please kindly approve, Mas Okto was oke. Thanks.|Y
90007072|Sick Leave Without Certificate|04/01/2019|04/01/2019|1|Sick leave due to eye swelling|Y
90004371|Sick Leave|04/01/2019|04/05/2019|4||Y
90007431|Sick Leave|04/01/2019|04/01/2019|1||Y

I have tried [this][1],

awk -F\| '{ while (NF < 7 || $NF == "") { brokenline=$0; getline; $0 = brokenline $0}; print }' cu_inf_20200902tst.csv > cu_inf_20200902tst1.csv

but i found the error warning :

awk: cmd. line:1: (FILENAME=cu_inf_20200902tst.csv FNR=19) fatal: grow_fields_arr: fields_arr: can't allocate 321069040 bytes of memory (Cannot allocate memory)

Any suggest to fix my problem? [1]: https://unix.stackexchange.com/questions/434979/fixing-malformed-csv-with-incorrect-new-line-chars-using-sed-or-perl-only

Upvotes: 4

Views: 276

Answers (3)

potong
potong

Reputation: 58430

This might work for you (GNU sed):

sed ':a;s/[^|]*/&/7;t;N;s/\n//;ta' file

Check to see if the current line contains 7 fields, if not, append the next line, remove the newline and repeat.

Upvotes: 1

RavinderSingh13
RavinderSingh13

Reputation: 133528

Considering that your first field id will be always 8 digits and no other field will be of 8 digits like it, if this is the case then you could try following.

awk '
{
  printf("%s%s", (FNR>1 ? (/^[0-9]{8}/?ORS:OFS) : ""), $0)
}
END{
  print ""
}' Input_file

Explanation: Adding detailed explanation for above.

awk '                                                   ##Starting awk program from here.
{
  printf("%s%s",(FNR>1?(/^[0-9]{8}/?ORS:OFS) ""), $0)   ##Using printf statement from here where checking condition if line is first line then check if line starts from 8 digits then print new line else print space.
}
END{                                                    ##Starting END block of this program from here.
  print ""                                              ##Printing a new line in here.
}' Input_file                                           ##Mentioning Input_file name here.

OR(in case you want to keep header separate itself then keep its condition separate itself)

awk '
FNR==1{
  print
  next
}
{
  printf("%s%s",$0!~/^[0-9]{8}/?OFS:(FNR>2?ORS:""),$0)
}
END{
  print ""
}' Input_file

Explanation: Adding detailed explanation for above.

awk '                                                     ##Starting awk program from here.
FNR==1{                                                   ##Checking condition if this is first line then do following.
  print                                                   ##Printing current line here.
  next                                                    ##next will skip all further statements from here.
}
{
  printf("%s%s",$0!~/^[0-9]{8}/?OFS:(FNR>2?ORS:""),$0)    ##Using printf for printing where checking condition if line starts from 8 digits then print space else check if line number is more than 2 then print new line or nothing with current line.
}
END{                                                      ##Starting END block of this program from here.
  print ""                                                ##Printing a new line in here.
}' Input_file                                             ##Mentioning Input_file name here.

Upvotes: 2

Ravi Saroch
Ravi Saroch

Reputation: 960

Please try the following.

Sed Solution

sed ':a;N;/\n[0-9]/!s/\n/ /;ta;P;D' input_file

awk Solution

awk '{printf "%s%s", (NR>1 ? (/^[0-9]/?ORS:OFS) : ""), $0} END{print ""}' input_file

Output of the following command

Employee ID|Time Type|Start Date|End Date|Number Of Days|Comment|Approved
90006731|Leave|04/02/2019|04/02/2019|1|annual leaves|Y
90005267|Leave|04/02/2019|04/02/2019|1||Y
90007366|Leave|04/02/2019|04/02/2019|1|* Take care of vehicle taxes  *Vehicle Repair  * Community service * Swimming|Y
90005052|Leave|04/02/2019|04/02/2019|1|Son's field trip|Y
90006253|Death of Wife/Husband/Child/Parent|04/01/2019|04/02/2019|2||Y
90007595|Leave|04/01/2019|04/01/2019|1|family plan|Y
90004064|Leave|08/18/2020|08/21/2020|3|Dear Mas Rama, Please kindly approve, Mas Okto was oke. Thanks.|Y
90007072|Sick Leave Without Certificate|04/01/2019|04/01/2019|1|Sick leave due to eye swelling|Y
90004371|Sick Leave|04/01/2019|04/05/2019|4||Y
90007431|Sick Leave|04/01/2019|04/01/2019|1||Y

for detail explanatiion: How to join lines not starting with specific pattern to the previous line in UNIX?

Upvotes: 1

Related Questions