Turning multi-line string into single comma-separated
StringBashShellCsvString Problem Overview
Let's say I have the following string:
something1: +12.0 (some unnecessary trailing data (this must go))
something2: +15.5 (some more unnecessary trailing data)
something4: +9.0 (some other unnecessary data)
something1: +13.5 (blah blah blah)
How do I turn that into simply
+12.0,+15.5,+9.0,+13.5
in bash?
String Solutions
Solution 1 - String
Clean and simple:
awk '{print $2}' file.txt | paste -s -d, -
Solution 2 - String
You can use awk
and sed
:
awk -vORS=, '{ print $2 }' file.txt | sed 's/,$/\n/'
Or if you want to use a pipe:
echo "data" | awk -vORS=, '{ print $2 }' | sed 's/,$/\n/'
To break it down:
awk
is great at handling data broken down into fields-vORS=,
sets the "output record separator" to,
, which is what you wanted{ print $2 }
tellsawk
to print the second field for every record (line)file.txt
is your filenamesed
just gets rid of the trailing,
and turns it into a newline (if you want no newline, you can dos/,$//
)
Solution 3 - String
cat data.txt | xargs | sed -e 's/ /, /g'
Solution 4 - String
This might work for you:
cut -d' ' -f5 file | paste -d',' -s
+12.0,+15.5,+9.0,+13.5
or
sed '/^.*\(+[^ ]*\).*/{s//\1/;H};${x;s/\n/,/g;s/.//p};d' file
+12.0,+15.5,+9.0,+13.5
or
sed 's/\S\+\s\+//;s/\s.*//;H;$!d;x;s/.//;s/\n/,/g' file
For each line in the file; chop off the first field and spaces following, chop off the remainder of the line following the second field and append to the hold space. Delete all lines except the last where we swap to the hold space and after deleting the introduced newline at the start, convert all newlines to ,
's.
N.B. Could be written:
sed 's/\S\+\s\+//;s/\s.*//;1h;1!H;$!d;x;s/\n/,/g' file
Solution 5 - String
$ awk -v ORS=, '{print $2}' data.txt | sed 's/,$//'
+12.0,+15.5,+9.0,+13.5
$ cat data.txt | tr -s ' ' | cut -d ' ' -f 2 | tr '\n' ',' | sed 's/,$//'
+12.0,+15.5,+9.0,+13.5
Solution 6 - String
awk one liner
$ awk '{printf (NR>1?",":"") $2}' file
+12.0,+15.5,+9.0,+13.5
Solution 7 - String
This should work too
awk '{print $2}' file | sed ':a;{N;s/\n/,/};ba'
Solution 8 - String
You can use grep
:
grep -o "+\S\+" in.txt | tr '\n' ','
which finds the string starting with +
, followed by any string \S\+
, then convert new line characters into commas. This should be pretty quick for large files.
Solution 9 - String
Try this easy code:
awk '{printf("%s,",$2)}' File1
Solution 10 - String
try this:
sedSelectNumbers='s".* \(+[0-9]*[.][0-9]*\) .*"\1,"'
sedClearLastComma='s"\(.*\),$"\1"'
cat file.txt |sed "$sedSelectNumbers" |tr -d "\n" |sed "$sedClearLastComma"
the good thing is the easy part of deleting newline "\n" characters!
EDIT: another great way to join lines into a single line with sed is this: |sed ':a;N;$!ba;s/\n/ /g'
got from here.
Solution 11 - String
A solution written in pure Bash:
#!/bin/bash
sometext="something1: +12.0 (some unnecessary trailing data (this must go))
something2: +15.5 (some more unnecessary trailing data)
something4: +9.0 (some other unnecessary data)
something1: +13.5 (blah blah blah)"
a=()
while read -r a1 a2 a3; do
# we can add some code here to check valid values or modify them
a+=("${a2}")
done <<< "${sometext}"
# between parenthesis to modify IFS for the current statement only
(IFS=',' ; printf '%s: %s\n' "Result" "${a[*]}")
Result: +12.0,+15.5,+9.0,+13.5
Solution 12 - String
Don't seen this simple solution with awk
awk 'b{b=b","}{b=b$2}END{print b}' infile
Solution 13 - String
With perl:
fg@erwin ~ $ perl -ne 'push @l, (split(/\s+/))[1]; END { print join(",", @l) . "\n" }' <<EOF
something1: +12.0 (some unnecessary trailing data (this must go))
something2: +15.5 (some more unnecessary trailing data)
something4: +9.0 (some other unnecessary data)
something1: +13.5 (blah blah blah)
EOF
+12.0,+15.5,+9.0,+13.5
Solution 14 - String
You can also do it with two sed calls:
$ cat file.txt
something1: +12.0 (some unnecessary trailing data (this must go))
something2: +15.5 (some more unnecessary trailing data)
something4: +9.0 (some other unnecessary data)
something1: +13.5 (blah blah blah)
$ sed 's/^[^:]*: *\([+0-9.]\+\) .*/\1/' file.txt | sed -e :a -e '$!N; s/\n/,/; ta'
+12.0,+15.5,+9.0,+13.5
First sed call removes uninteresting data, and the second join all lines.
Solution 15 - String
You can also print like this:
Just awk: using printf
bash-3.2$ cat sample.log
something1: +12.0 (some unnecessary trailing data (this must go))
something2: +15.5 (some more unnecessary trailing data)
something4: +9.0 (some other unnecessary data)
something1: +13.5 (blah blah blah)
bash-3.2$ awk ' { if($2 != "") { if(NR==1) { printf $2 } else { printf "," $2 } } }' sample.log
+12.0,+15.5,+9.0,+13.5
Solution 16 - String
Another Perl solution, similar to Dan Fego's awk:
perl -ane 'print "$F[1],"' file.txt | sed 's/,$/\n/'
-a
tells perl to split the input line into the @F array, which is indexed starting at 0.
Solution 17 - String
Well the hardest part probably is selecting the second "column" since I wouldn't know of an easy way to treat multiple spaces as one. For the rest it's easy. Use bash substitutions.
# cat bla.txt
something1: +12.0 (some unnecessary trailing data (this must go))
something2: +15.5 (some more unnecessary trailing data)
something4: +9.0 (some other unnecessary data)
something1: +13.5 (blah blah blah)
# cat bla.sh
OLDIFS=$IFS
IFS=$'\n'
for i in $(cat bla.txt); do
i=$(echo "$i" | awk '{print $2}')
u="${u:+$u, }$i"
done
IFS=$OLDIFS
echo "$u"
# bash ./bla.sh
+12.0, +15.5, +9.0, +13.5
Solution 18 - String
Yet another AWK solution
Run
awk '{printf "%s", $c; while(getline){printf "%s%s", sep, $c}}' c=2 sep=','
to use the 2nd column to form the list separated by commas. Give the input as usual in standard input or as a file name argument.