Home > Blockchain >  How to use IFS= read when you have two input files to perform a sed to replace two values on specifi
How to use IFS= read when you have two input files to perform a sed to replace two values on specifi

Time:06-23

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.

  • Related