file1.txt
[fields:WinSpc:defect]
a=b
b=c
hello=hi
[fields:ROCKET PROJECT:ticket]
description=Descrtiption
status=status
[fields:PROJECT_Nexus:defect]
title=summary
priority=Priority_hello
file2.csv
WinSpc,projects.winspc
ROCKET PROJECT,projects.rocket_project
PROJECT_Nexus,projects.project-nexus
I need to match these two files and desired output would be :
output.txt
[fields:winspc:defect]
a=b
b=c
hello=hi
[fields:rocket_project:ticket]
description=Descrtiption
status=status
[fields:project-nexus:defect]
title=summary
priority=Priority_hello
Just the name should be changed,
i have tried using
grep -Fwf, diff --breif,
and awk options but not getting desired output. Still learning these things. Any suggestions would be very helpful. Thanks in advance.
A more scalable Awk
logic can be done something as below.
Re-affirming the requirement for future readers, the .csv
file has a field,replacement-of-field
1 pair stored in multiple lines. For all those field
in .csv
the corresponding entries in .txt
file should be replaced with replacement-of-field
1. replcement-of-field actually involves only the part after the dot
The below command does the job as intended.
awk 'FNR==NR{split($2,list,"."); replacement[$1]=list[2]; next} \
{for (i in replacement){ if (match($0,i)) {gsub(i,replacement[i],$0); break} }}1 ' \
FS="," file2.csv file1.txt
produces an output as OP
needed,
[fields:winspc:defect]
a=b
b=c
hello=hi
[fields:rocket_project:ticket]
description=Descrtiption
status=status
[fields:project-nexus:defect]
title=summary
priority=Priority_hello
Throwing in a bit of explanation,
FNR==NR
logic ensures the command after it within {}
is run first for the .csv
file. Note that .csv
file is read with field-separator ,
split($2,list,".");replacement[$1]=list[2]; next
ensures that the second column of the file is split by .
and a hash-map is created with index set to value to be replaced and the value as actual value to be replaced. This is done for all the lines in the .csv
file
- Now on the
.txt
file, for each line is checked to see if the value to be replaced is present, if present it is replaced with the replacement value.
A sed
one-liner:
sed 's#,projects.#/#;s#.*#/fields/s/&/\;#' file2.csv | sed -f - file1.txt
How it works:
Transform file2.csv into sed
substitute commands. So the initial code
sed 's#,projects.#/#;s#.*#/fields/s/&/\;#' file2.csv
outputs:
/fields/s/WinSpc/winspc/;
/fields/s/ROCKET PROJECT/rocket_project/;
/fields/s/PROJECT_Nexus/project-nexus/;
Run the resulting substitute commands on file1.txt.
Output:
[fields:winspc:defect]
a=b
b=c
hello=hi
[fields:rocket_project:ticket]
description=Descrtiption
status=status
[fields:project-nexus:defect]
title=summary
priority=Priority_hello
Taken into consideration your comments, this looks an exercise to replace values that follows fields:
in txt file, using replacement values from another file where the "fields" value is a kind of key.
Have a look in this approach:
$ readarray -t a < <(grep -e "\[fields:" a.txt |cut -d: -f2)
$ for ((i=0;i<${#a[@]};i++));do a[i]=s/${a[i]}/$(grep -e "${a[i]}" b.txt |cut -d, -f2 |cut -d. -f2)/g\;;done
$ sed -f <(echo "${a[@]}") a.txt
Output:
[fields:winspc:defect]
a=b
b=c
hello=hi
[fields:rocket_project:ticket]
description=Descrtiption
status=status
[fields:project-nexus:defect]
title=summary
priority=Priority_hello
Explanation:
# grep the first file a.txt for all the fields: and keep the second part, i.e WinScp . Store all those findings in an array
$ readarray -t a < <(grep -e "\[fields:" a.txt |cut -d: -f2)
$ declare -p a #print the array to see what is inside
#Bash Output: declare -a a=([0]="WinSpc" [1]="ROCKET PROJECT" [2]="PROJECT_Nexus")
# Iterate through the array and with the stored value (i.e WinSpc) grep the second file
# (b.txt in my test) and get the second field after comma. Store changes in the same array.
$ for ((i=0;i<${#a[@]};i++));do a[i]=s/${a[i]}/$(grep -e "${a[i]}" b.txt |cut -d, -f2 |cut -d. -f2)/g\;;done
$ declare -p a #print the array again. Now array looks like a sed pattern.
# Bash Output: declare -a a=([0]="s/WinSpc/winspc/g;" [1]="s/ROCKET PROJECT/rocket_project/g;" [2]="s/PROJECT_Nexus/project-nexus/g;")
# We can then apply all the sed patterns stored in array to replace values of text file (a.txt)
$ sed -f <(echo "${a[@]}") a.txt
Other solutions with AWK, etc may provide a more efficient code .