alvas
alvas

Reputation: 122022

Column wise concatenation X no. of time

I have a file with some strings delimited by newline, in.txt:

$ echo -e 'a\nb\nc' > in.txt
$ cat in.txt 
a
b
c

And I need to concat a certain fix values to the file for each line in in.txt column-wise, so first I did:

$ yes '0.0' | head -n 3
0.0
0.0
0.0

Then paste it:

$ yes '0.0' | head -n 3 > 0s
$ paste in.txt 0s 
 a  0.0
 b  0.0
 c  0.0

The question is how do I perform the column wise concatenation X no. of times? Imagine X is 100,000 , manually typing in paste in.txt 0s 0s 0s ... is not feasible.

Upvotes: 3

Views: 143

Answers (4)

bishop
bishop

Reputation: 39364

I'd break the problem into two parts. First, create a tab-separated file of the desired dimensions and content (R rows by C columns, each cell containing string F). Then, paste that generated file onto the existing file:

R=$(wc -l < in.txt)   # num rows to generate, in this case same num lines as input
C=100000              # num columns to generate
F=0.0                 # fixed value

paste in.txt <(yes $F | head -$(($R * $C)) | pr -t$C -s$'\t')

For the sample input given, with C=5 columns, I get:

a       0.0     0.0     0.0     0.0     0.0
b       0.0     0.0     0.0     0.0     0.0
c       0.0     0.0     0.0     0.0     0.0

Breaking that pipeline down, inside out:

  • yes $F generates a stream of fixed values
  • head -$(($R * $C)) cuts the yes stream off after we've generated all the cells we need
  • pr -t$C -s$'\t' rotates the stream into a tab-separated table having the number of columns we want
  • <() puts all the above into an (essentially) temporary file
  • paste in.txt <() adjoins the two files, row-wise

Upvotes: 3

Benjamin W.
Benjamin W.

Reputation: 52112

Sed solutions

You could generate the string you want with printf and substitute the end of each line using sed:

$ num=5
$ sed 's/$/'"$(for ((i=0; i<num; ++i)); do printf '\t%s' '0.0'; done)"'/' in.txt
a       0.0     0.0     0.0     0.0     0.0
b       0.0     0.0     0.0     0.0     0.0
c       0.0     0.0     0.0     0.0     0.0

where the value assigned to num is the number of columns to be added to your file.

The substitution replaces each line end ($) with the output of this command:

for (( i=0; i < num; ++i )); do
    printf '\t%s' '0.0'
done

If you don't mind using seq, this could be simplified to

sed 's/$/'"$(printf '\t0.0%.0s' $(seq 1 $num))"'/' in.txt

i.e., the command in the substitution is the one-liner

printf '\t0.0%.0s' $(seq 1 $num)

See for example the question How can I repeat a character in bash? for many options how to repeat a string in Bash using various tools.

Awk solution

This takes num as the number of columns to be added and uses a tab as the field separator:

awk -v num=5 -v OFS="\t" '{for (i=1; i<=num; ++i) $(NF+1) = "0.0"}1' in.txt

The for loop assigns 0.0 to the field one past the last, num times; the 1 gets the line printed.

Upvotes: 2

Amal Dev S
Amal Dev S

Reputation: 68

What about something like this

paste in.txt \`printf '0s %.0s' {1..$X}\`

I got that printf part from https://superuser.com/questions/86340/linux-command-to-repeat-a-string-n-times

Upvotes: 1

Mustafa DOGRU
Mustafa DOGRU

Reputation: 4112

you can also use for loop as below;

paste in.txt $(for i in {1..3}; do echo '0s'; done)

or

paste in.txt <(for i in {1..X}; do echo $(yes 0.0 | head -3); done)

or

paste in.txt <(for i in {1..3}; do echo $(yes 1.1 | head -$(wc -l in.txt| awk '{print $1}')); done)

Eg:

user@host:/tmp$ paste in.txt <(for i in {1..3}; do echo $(yes 1.1 | head -3); done)
a   1.1 1.1 1.1
b   1.1 1.1 1.1
c   1.1 1.1 1.1

Upvotes: 1

Related Questions