yoyo31
yoyo31

Reputation: 11

How to append string into text file

data.txt

height= 6'1" age= shoe-size=9.5 sex= M
height= 6'5" age= shoe-size=9.0 sex= M
height= 5'11" age= shoe-size=8.5 sex= F
height= 5'9" age= shoe-size=11.5 sex= M
height= 4'11" age= shoe-size=7.5 sex= F
height= 6'4" age= shoe-size=9.5 sex= M

age.txt

21
23
22
19
34
27

How do I grab the information from the age.txt and place it into data.txt, putting each number following the other into the age portion of data.txt?

Is there a way to do a for loop for the number of lines in my file and then look for 'age' and every time I see age, replace it with the number in age.txt

Expected output

height= 6'1" age=21 shoe-size=9.5 sex= M
height= 6'5" age=23 shoe-size=9.0 sex= M
height= 5'11" age=22 shoe-size=8.5 sex= F
height= 5'9" age=19 shoe-size=11.5 sex= M
height= 4'11" age=34 shoe-size=7.5 sex= F
height= 6'4" age=27 shoe-size=9.5 sex= M

Upvotes: 1

Views: 131

Answers (3)

Jetchisel
Jetchisel

Reputation: 7791

Using bash4 index arrays.

mapfile -t data < data.txt
mapfile -t age <age.txt

for i in "${!data[@]}"; do echo "${data[$i]//age=/age="${age[$i]}"}"; done

Output is this.

height= 6'1" age=21 shoe-size=9.5 sex= M
height= 6'5" age=23 shoe-size=9.0 sex= M
height= 5'11" age=22 shoe-size=8.5 sex= F
height= 5'9" age=19 shoe-size=11.5 sex= M
height= 4'11" age=34 shoe-size=7.5 sex= F
height= 6'4" age=27 shoe-size=9.5 sex= M

mapfile aka readarray is a bash4+ feature.

The ${!data[@]} means you're looking for the index of an array and ${data[@]} is the array.

Or using while loop and read read, so basically it is just reading the two files inside a while loop.

while IFS= read -r line_in_data <&3
  read -r line_in_age; do
  printf '%s\n' "${line_in_data//age=/age=$line_in_age}"
done 3<data.txt <age.txt

Should print the same output.

height= 6'1" age=21 shoe-size=9.5 sex= M
height= 6'5" age=23 shoe-size=9.0 sex= M
height= 5'11" age=22 shoe-size=8.5 sex= F
height= 5'9" age=19 shoe-size=11.5 sex= M
height= 4'11" age=34 shoe-size=7.5 sex= F
height= 6'4" age=27 shoe-size=9.5 sex= M

POSIX sh solution.

#!/bin/sh

while read -r column1_in_data column2_in_data column3_in_data rest_of_columns_in_data <&3
  read -r line_in_age; do
  printf '%s\n' "$column1_in_data $column2_in_data $column3_in_data$line_in_age $rest_of_columns_in_data"
done 3<data.txt <age.txt

the <&3 is a redirection so the first read will read from FD (file descriptor 3.)

The ${var//search/rep} is a bash specific P.E. (parameter expansion.)

Awk can do better/faster on large set of files/data I believe.

Upvotes: 3

Benjamin W.
Benjamin W.

Reputation: 52132

You could do it with a bunch of cut and paste and process substitution:

paste -d ' ' \
    <(paste -d'\0'  \
        <(cut -d' ' -f-3 data.txt) \
        age.txt) \
    <(cut -d' ' -f4- data.txt)

The outer paste command uses a blank as the delimiter to paste the output of the inner paste and the outer cut together.

The inner paste uses a null delimiter so there is no blank between age= and the age value.

This being said, the input file format seems inconsistent regarding the spacing around =.

Upvotes: 1

David C. Rankin
David C. Rankin

Reputation: 84561

Using awk and getline provides a very simple and efficient solution, e.g.

awk '{getline age < "age.txt"; $3=$3 age}1' data.txt

Above you are simply using getline to read from age.txt into the variable age and then appending age to the 3rd field from data.txt.

Another way so long as "age=" only appears once in the line would be:

awk '{getline age < "age.txt"; sub(/age=/,"age=" age)}1' data.txt

Example Use/Output

You can just copy and middle-mouse paste into an xterm in the directory where your files are located, e.g.

$ awk '{getline age < "age.txt"; $3=$3 age}1' data.txt
height= 6'1" age=21 shoe-size=9.5 sex= M
height= 6'5" age=23 shoe-size=9.0 sex= M
height= 5'11" age=22 shoe-size=8.5 sex= F
height= 5'9" age=19 shoe-size=11.5 sex= M
height= 4'11" age=34 shoe-size=7.5 sex= F
height= 6'4" age=27 shoe-size=9.5 sex= M

Upvotes: 2

Related Questions