Reputation: 11
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
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
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
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