Reputation: 6050
How do you read/process 2 files in sync with each other in bash?
I have 2 text files which have the same number of lines/items in them. One file is
a
b
c
The other file is
1
2
3
How do I loop through these files in sync so that a
is associated with 1
, b->2, c->3?
I thought that I could read in the files as an array and then process them with an index but it seems like my syntax/logic is incorrect.
So doing f1=$(cat file1)
makes f1 = a b c
. I thought doing f1=($(cat file1))
would make it into an array but it makes f1=a
and thus no array for me to process.
In case anyone was wondering what my messed up code is:
hostnames=($(cat $host_file))
# trying to read in as an array, which apparently is incorrect
roles=($(cat $role_file))
for i in {0..3}
do
echo ${hostnames[$i]}
# wanted to iterate through each element in the file/array
# but there is only one object instead of N objects
echo ${roles[$i]}
done
Upvotes: 8
Views: 691
Reputation: 85775
A concise and flexible solution to this problem is the core-util pr
:
# space separated
$ pr -mts' ' file1 file2
a 1
b 2
c 3
# -> separated
$ pr -mts' -> ' file1 file2
a -> 1
b -> 2
c -> 3
See man pr
for more information.
Upvotes: 2
Reputation: 17188
Pure Bash:
IFS=$'\n'
hostnames=( $( <hostnames.txt ) )
roles=( $( <roles.txt ) )
for idx in ${!hostnames[@]}; do # loop over array indices
echo -e "${hostnames[idx]} ${roles[idx]}"
done
or after gniourf_gniourf's comment
mapfile -t hostnames < hostnames.txt
mapfile -t roles < roles.txt
for idx in ${!hostnames[@]}; do # loop over array indices
echo -e "'${hostnames[idx]}' '${roles[idx]}'"
done
Upvotes: 0
Reputation: 1482
Your way:
host_file=host1
role_file=role1
hostnames=( $(cat $host_file) )
roles=( $(cat $role_file) )
(( cnt = ${#hostnames[@]} -1 ))
echo "cnt is $cnt"
for (( i=0;i<=$cnt;i++))
do
echo "${hostnames[$i]} -> ${roles[$i]}"
done
Upvotes: 2
Reputation: 37569
two examples with awk:
awk '{print $0, NR}' file1
and - much better :-)
awk 'NR==FNR {a[NR]=$0;next};{print a[FNR], $0}' file1 file2
..output is always:
a 1
b 2
c 3
Upvotes: 2
Reputation: 3756
Code for GNU sed:
with file1
in front:
sed -r 's#(.*)#s/(.*)/\1 \\1/;$!n#' file1|sed -rf - file2
or
with file2
in front:
sed -r 's#(.*)#s/(.*)/\\1 \1/;$!n#' file2|sed -rf - file1
Both leads to the same output:
a 1 b 2 c 3 d 4 e 5 f 6 g 7
Upvotes: 2
Reputation: 3301
Use paste
(invocation) to combine the files, then process one line of the combined file at a time:
paste file1 file2 |
while read -r first second
do
echo $first
echo $second
done
Upvotes: 11
Reputation: 77085
You can use file descriptors:
while read -r var_from_file1 && read -r var_from_file2 <&3; do
echo "$var_from_file1 ---> $var_from_file2"
done <file1 3<file2
a ---> 1
b ---> 2
c ---> 3
Upvotes: 17