I have a file names fileA.txt
with "x" quantity of line numbers. I need to replace a string named No_IP_Found
with an IPAddr but on specific lines. I have the line numbers I need to replace in a file named linenum.txt
(lets say line 1
and 4
); and another file name ipaddr.txt
with the IpAddresses (2 IP Address are listed; lets say 192.168.1.1
, 192.168.1.2
). The files always match linumbers qty with IP Address. So line 1
belongs to 192.168.1.1
, line 4
belongs to 192.168.1.2
and so on.
I know i can use sed
with specified line I want to replace; example line 1
to be replace with sed
is: sed '1s/No_IP_Address/192.168.1.1/' fileA.txt
Im using IFS= read
to perform this operation but I dont know how to makee it worked when I have two input files.
$ cat linenum.txt
1
4
$ cat ipaddr.txt
192.168.1.1
192.168.1.2
$ cat fileA.txt
SW-01-PR No_IP_Found POE_SWITCH
SW-0W-XT 192.168.10.10 HR_SWITCH
SW-2K-RR 192.168.10.11 GYM_SWITCH
SW-3F-PR No_IP_Found 3F-SWITCH
SW-11-EE 192.168.10.20 EE-SWITCH
Desired New Output
SW-01-PR 192.168.1.1 POE_SWITCH
SW-0W-XT 192.168.10.10 HR_SWITCH
SW-2K-RR 192.168.10.11 GYM_SWITCH
SW-3F-PR 192.168.1.2 3F-SWITCH
SW-11-EE 192.168.10.20 EE-SWITCH
I have the following code; but didnt worked; I have no idea how to make two inputs worked and use sed to replace the lines with the specific string on specific line. Or maybe awk?
while IFS= read -r linenum && IFS= read -r ipadd <&3; do
sed "${linenum}s/No_IP_Found/$ipadd" fileA.txt
done <linenum.txt 3<ipaddr.txt
Any help appreciated. Thanks
CodePudding user response:
awk '
NR==FNR { a[$1]=$2; next }
$2 == "No_IP_Found" && a[FNR]{$2 = a[FNR]}1
' <(paste linenum.txt ipaddr.txt) fileA.txt|column -t
SW-01-PR 192.168.1.1 POE_SWITCH
SW-0W-XT 192.168.10.10 HR_SWITCH
SW-2K-RR 192.168.10.11 GYM_SWITCH
SW-3F-PR 192.168.1.2 3F-SWITCH
SW-11-EE 192.168.10.20 EE-SWITCH
Formatting rows and using inplace
awk -i inplace '
NR==FNR { a[$1]=$2; next }
$2 == "No_IP_Found" && a[FNR]{$2 = a[FNR]}
{
printf "%s %s %-16s %s\n", $1, FS, $2, $3
}
' inplace::enable=0 <(paste linenum.txt ipaddr.txt) inplace::enable=1 fileA.txt
$ cat fileA.txt
SW-01-PR 192.168.1.1 POE_SWITCH
SW-0W-XT 192.168.10.10 HR_SWITCH
SW-2K-RR 192.168.10.11 GYM_SWITCH
SW-3F-PR 192.168.1.2 3F-SWITCH
SW-11-EE 192.168.10.20 EE-SWITCH
CodePudding user response:
Fixing a syntax issue with the sed
script (adding a /
to the end), adding the -i
option (per Barmar) to update fileA.txt
with the changes
while IFS= read -r linenum && IFS= read -r ipadd <&3; do
sed -i "${linenum}s/No_IP_Found/$ipadd/" fileA.txt
done <linenum.txt 3<ipaddr.txt
Since the two input files only contain single fields (ie, no delimiters to worry about) there's actually no need (in this case) for the IFS=
clauses so this should also work:
while read -r linenum && read -r ipadd <&3; do
sed -i "${linenum}s/No_IP_Found/$ipadd/" fileA.txt
done <linenum.txt 3<ipaddr.txt
Since the two input files have the same number of lines we could also use paste
to feed a single read
like such:
while read -r linenum ipadd; do
sed -i "${linenum}s/No_IP_Found/$ipadd/" fileA.txt
done < <(paste linenum.txt ipaddr.txt)
CodePudding user response:
You should certainly use awk
for this, but if you're going to use sed
one fragile option is to build up the command string and just run sed
once. Something like:
$ paste linenum.txt ipaddr.txt | { while read line ip; do
cmd="$cmd -e ${line}s/No_IP_Found/$ip/"; done;
sed $cmd fileA.txt ; }
SW-01-PR 192.168.1.1 POE_SWITCH
SW-0W-XT 192.168.10.10 HR_SWITCH
SW-2K-RR 192.168.10.11 GYM_SWITCH
SW-3F-PR 192.168.1.2 3F-SWITCH
SW-11-EE 192.168.10.20 EE-SWITCH
Note that sed -i
is a tragedy and should never be used, and using it in a loop to repeatedly edit the same file is a recipe for disaster. It is much cleaner to write your output somewhere else. Also note that despite its name, "in-place" editing (almost) never actually edits the file in place. It (almost always) creates a new file and renames it. This may not be an issue, but people using -i
options ought to be aware of this fact.