5

I have a file csv :

data1,data2,data2
data3,data4,data5
data6,data7,data8

I want to convert it to (Contained in a variable):

variable=data1,data2,data2%0D%0Adata3,data4,data5%0D%0Adata6,data7,data8

My attempt :

data=''
cat csv | while read line
do
data="${data}%0D%0A${line}"
done
echo $data  # Fails, since data remains empty (loop emulates a sub-shell and looses data)

Please help..

jww
  • 97,681
  • 90
  • 411
  • 885
Yugal Jindle
  • 44,057
  • 43
  • 129
  • 197

8 Answers8

21

Simpler to just strip newlines from the file:

tr '\n' '' < yourfile.txt > concatfile.txt
Marc B
  • 356,200
  • 43
  • 426
  • 500
6

In bash,

data=$(
while read line
do
  echo -n "%0D%0A${line}"
done < csv)

In non-bash shells, you can use `...` instead of $(...). Also, echo -n, which suppresses the newline, is unfortunately not completely portable, but again this will work in bash.

Andrew Schulman
  • 3,395
  • 1
  • 21
  • 23
4

Some of these answers are incredibly complicated. How about this.

 data="$(xargs printf ',%s' < csv | cut -b 2-)"

or

 data="$(tr '\n' ',' < csv | cut -b 2-)"

Too "external utility" for you?

IFS=$'\n', read -d'\0' -a data < csv

Now you have an array! Output it however you like, perhaps with

data="$(tr ' ' , <<<"${data[@]}")"

Still too "external utility?" Well fine,

data="$(printf "${data[0]}" ; printf ',%s' "${data[@]:1:${#data}}")"

Yes, printf can be a builtin. If it isn't but your echo is and it supports -n, use echo -n instead:

data="$(echo -n "${data[0]}" ; for d in "${data[@]:1:${#data[@]}}" ; do echo -n ,"$d" ; done)"

Okay, now I admit that I am getting a bit silly. Andrew's answer is perfectly correct.

sorpigal
  • 25,504
  • 8
  • 57
  • 75
3

I would much prefer a loop:

for line in $(cat file.txt); do echo -n $line; done

Note: This solution requires the input file to have a new line at the end of the file or it will drop the last line.

Julien Carsique
  • 3,915
  • 3
  • 22
  • 28
Alexandre Mélard
  • 12,229
  • 3
  • 36
  • 46
2

Another short bash solution

variable=$(
  RS=""
  while read line; do
    printf "%s%s" "$RS" "$line"
    RS='%0D%0A'
  done < filename
)
glenn jackman
  • 238,783
  • 38
  • 220
  • 352
1

A very simple single-line solution which requires no extra files as its quite easy to understand (I think, just cat the file together and perform sed-replace):

output=$(echo $(cat ./myFile.txt) | sed 's/ /%0D%0A/g')
BiS
  • 501
  • 4
  • 17
1
awk 'END { print r }
{ r = r ? r OFS $0 : $0 }
  ' OFS='%0D%0A' infile  

With shell:

data=

while IFS= read -r; do
  [ -n "$data" ] &&
     data=$data%0D%0A$REPLY ||
    data=$REPLY
done < infile

printf '%s\n' "$data"   

Recent bash versions:

data=

while IFS= read -r; do
  [[ -n $data ]] &&
     data+=%0D%0A$REPLY ||
    data=$REPLY
done < infile

printf '%s\n' "$data"
Dimitre Radoulov
  • 27,252
  • 4
  • 40
  • 48
0

Useless use of cat, punished! You want to feed the CSV into the loop

while read line; do 
 # ...
done < csv
themel
  • 8,825
  • 2
  • 32
  • 31