Concatenate all fields after specific one in a file with variable NF

Viewed 71

I have a file like this:

ID1 as;uh;2
ID2 uh;3 jk PASS
ID3 PASS
ID4 as;uh;PASS kk;3 rt
ID5 as
ID6 PASS PASS uh 3;4
ID7 jk;34 hy

I would like to concatenate all fields after the first, separating them by | and getting the following:

ID1 as;uh;2
ID2 uh;3|jk|PASS
ID3 PASS
ID4 as;uh;PASS|kk;3|rt
ID5 as
ID6 PASS|PASS|uh|3;4
ID7 jk;34|hy

I was trying something like this, but I am not sure how to automatically concatenate all columns after the first one, instead of manually indicating the number of columns (because in my real file, some rows present more than 15 fields).

awk -v OFS='\t' '{ $2=$2"|"$3"|"$4;    #merge cols after the first one   
        for (i=3;i<NF;i++) $(i)=""} 1'    #remove cols after 2nd one and print it                      

Do you know how can I achieve it?

5 Answers

With your shown samples, please try following awk code.

awk '
match($0,/^[^ ]* /){
  first=substr($0,RSTART,RLENGTH)
  second=substr($0,RSTART+RLENGTH)
  gsub(/ /,"|",second)
  print first second
}
'  Input_file

You may use this awk:

awk '{
   printf "%s", $1 OFS $2
   for (i=3; i<=NF; ++i)
      printf "|%s", $i
   print ""
}' file

ID1 as;uh;2
ID2 uh;3|jk|PASS
ID3 PASS
ID4 as;uh;PASS|kk;3|rt
ID5 as
ID6 PASS|PASS|uh|3;4
ID7 jk;34|hy

Another solution using match:

awk 'match($0, /[[:blank:]]+/) {
   s = substr($0, RSTART+RLENGTH)
   gsub(/[[:blank:]]/, "|", s)
   print $1, s
}' file

With GNU sed:

$ sed 's/ /|/2g' ip.txt
ID1 as;uh;2
ID2 uh;3|jk|PASS
ID3 PASS
ID4 as;uh;PASS|kk;3|rt
ID5 as
ID6 PASS|PASS|uh|3;4
ID7 jk;34|hy

2g will replace only from the second match onwards.

Using awk first to replace all space to pipe, then the first pipe back to a space:

$ awk '{gsub(/ /,"|");sub(/\|/," ")}1' file

ID1 as;uh;2
ID2 uh;3|jk|PASS
ID3 PASS
...

If you don't want to convert trailing spaces to a pipe, another option could be setting the output field separator (OFS) to a pipe char and then replace the first occurrence with a space using sub.

The $1=$1 parts reconstructs the $0 using the OFS.

 awk -v OFS="|" '{$1=$1;sub("\\|"," ")}1' file

Output

ID1 as;uh;2
ID2 uh;3|jk|PASS
ID3 PASS
ID4 as;uh;PASS|kk;3|rt
ID5 as
ID6 PASS|PASS|uh|3;4
ID7 jk;34|hy
Related