1

With AWK and SED patterns i ended up with a file similar to

|
9000
3000
1000
0000
0000
2000
1000
2000
|
5669000
518000
3000
16000
0000
28000
2241000
2841000
|
9020000
453000
520000
4000
2852000
5191000
75000
|

Is it possible to concatenate the lines seperated between the "|" into a single line separated by commas?

9000,3000,1000,0000,0000,2000,1000,2000
5669000,518000,3000,16000,0000,28000,2241000,2841000
9020000,453000,520000,4000,2852000,5191000,75000

i used paste to do this but it produces undesired results since the number of lines between the "|" is not equal.

3

awk solution. Suspect it's a bit long-winded.

$ awk 'BEGIN{RS="|"}NF>1{print substr(gensub(/\n/,",","g"),2,length($0)-2)}' file
9000,3000,1000,0000,0000,2000,1000,2000
5669000,518000,3000,16000,0000,28000,2241000,2841000
9020000,453000,520000,4000,2852000,5191000,75000
$

Try it online!

  • 2
    It's not really any less long-winded, but you could do it all via separators i.e. awk 'BEGIN{RS="\n?\\|\n"; FS="\n"; OFS=","} {$1=$1} NR>1' – steeldriver Aug 17 '18 at 21:53
  • 1
    Thanks for all the awesome answers. it was much more interesting to pass this entire solution into an echo statement(i was generating this awk statement to run as a part of another script!) – Maran Ganesh Aug 27 '18 at 19:26
2

This seems to work nicely:

$ tr "|\n" "\n," < input | sed 's/^,//;s/,$//'
9000,3000,1000,0000,0000,2000,1000,2000
5669000,518000,3000,16000,0000,28000,2241000,2841000
9020000,453000,520000,4000,2852000,5191000,75000

We use tr to translate |s into new lines, and newlines into ,s. We then take the resultant output and strip and leading or trailing ,s with sed.

  • 1
    Good elegant solution. But I feel compelled to mention you've an unnecessary cat there. – steve Aug 17 '18 at 21:36
  • 1
    I have saved the poor cat from useless toil. – DopeGhoti Aug 17 '18 at 21:43
1
sed ':L; ${s/\n/,/g; s/,|,/\n/g; s/|,\|,|//g};  N; bL;' file
1

One way to do it could be :

perl -nF'\|\n' -a0777e 'print s/\n(?!\z)/,/gr for @F' input.file

Explanation:

  • Slurp the file -0777 and then have it split on -F\|\n ,i.e., wherever we see a pipe character followed by a newline character.
  • The -a option will store the split fields into the array @F, which is zero-indexed.
  • The first element of the array @F, viz., $F[0] would be empty so wouldn't show up when it is printed.
  • The for loop loops over all the elements of the array @F and for each element, it changes all those newlines that do not see an end-of-string to their immediate right, (?!\z), are substituted for a comma.

Output:

9000,3000,1000,0000,0000,2000,1000,2000
5669000,518000,3000,16000,0000,28000,2241000,2841000
9020000,453000,520000,4000,2852000,5191000,75000

Another method using POSIXly sed editor. Here we load the pattern space as much as is needed to arrive at the decision to print it:

sed -e '
    /|$/!ba
    1d;s/\n|$//
    :b;y/\n/,/;b
    :a;$bb
    N;H;s/.*//;x;D
' input.file

In this method we slurp the file:

sed -e '
    $!{                 ;# provided we"re not at the eof
        N;H;s/.*//;x;D  ;# we stick the next line to the PS & keep doing it till we hit the eof.
    }

    ;# here we have the whole file loaded into the pattern space, PS
    s/^|\n//;s/\n|$//   ;# take away the leading and trailing pipes
    s/\n|\n/,/g         ;# the internal pipes are changed to commas
    y/\n,/,\n/          ;# interchange the newlines <=> commas
' input.file

With GNU sed it can be done by setting up a do-until loop to load up the pattern space while we have not yet seen the |. Note: with this we are assuming the last and first lines of the input are necessarily a |.

sed -e '
    1d
    :loop
        $!N
        s/\n|//
    Tloop
    y/\n/,/
' input.file
1
awk -vRS='|' -vOFS=, '$1=$1""' infile
  • The RS='|', changes the awk's default Record Seperator which it \newline to a pipe | instead.
  • The OFS=,, changes the awk's default Output Field Seperator which is a space to a comma , instead.

  • The $1==$1 (you can use any filed) causes the re-evaluation of $0 (known whole line in awk) and will join the fields based on RS as | and OFS as ,.

  • Double quotes in '$1=$1""' is used to force awk to string assignment, so a line with only zero(s) will not be deleted.

  • Output is:

    9000,3000,1000,0000,0000,2000,1000,2000
    5669000,518000,3000,16000,0000,28000,2241000,2841000
    9020000,453000,520000,4000,2852000,5191000,75000
    

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.