Skip to content
Advertisement

In bash got unwanted newlines after sed and cat >>

I’m trying to substitute some lines in /etc/hosts file with my script here:

#!/bin/bash

hosts_file_path="/etc/hosts"

nas_servers=( 'mynas01' 'mynas02' )

strange_string="<00>"

for nas_name in ${nas_servers[@]}; do
    printf '%lsn' "$nas_name"
    r="$(nmblookup "$nas_name")"
    if [[ ! -z "$r" ]] && [[ "$r" != "name_query" ]]; then
        l=${#r}
        ls=${#strange_string}
        cl=$(($l-$ls))
        echo "$cl"
        s="${r:0:cl}"
        printf '"%ls"n' "$s"
        res="$(grep -i "$nas_name" "$hosts_file_path")"
        echo "$res"
        if [ ! -z "$res" ]; then
            sr="s/.*${nas_name}.*//g"
            echo "$sr"
            sed -i "$sr" "$hosts_file_path"
        fi
        printf '%lsn' "$s" >> "$hosts_file_path"
    fi
done 

It searches e.g. for lines like

192.168.1xx.xxx mynas01

and replaces the line (if it’s found) with a sed command to nothing, but adds afterwards e.g. to

192.169.1xx.xxx mynas01 

I’m having to do (?) this because my LAN network addresses are changing very often (exactly: at each working day, but not always in a working session), so editing everytime the /etc/hosts file is not very useful, even to setup stuff like SNMP is (for two servers) a little too much overhead for me – I just want o put this script in a cron job or in rc.local and to avoid smblookups.

Now my question(s): If I making it in this way, there will be more empty newlines after the end of file and/bewtween the added text, How can I avoid this and is there a shorter way for that?

Till now I got as result (/etc/hosts):

127.0.0.1       localhost
127.0.1.1       hostname.fqdn.example.com    hostnam

(^ the space here got more and more by each call of my script, more newlines and more newlines) 


192.168.1xx.101 mynas01
192.168.1xx.102 mynas02

Thanks

Advertisement

Answer

The issue is that your sed command, instead of deleting the line of interest, turns it into an empty line, so in effect you blank out an old NAS entry while adding a new line for it, which keeps adding lines.

Use the following sed command instead, which deletes the matching line:

sr="/${nas_name}/ d"

or, more robustly, to rule out false positives:

sr="/[[:blank:]]${nas_name}[[:blank:]]*$/ d"

Since a double-quoted string is used, you generally have to use $ for $ chars. that the shell should not expand.
However, the shell leaves something that is not a syntactically valid variable reference alone, so $/ is passed through to sed as-is.
For stricter separation of the shell expanded part (double-quoted) and the Sed script (single-quoted), you can use the following, which, however, is harder to read: sr='/[[:blank:]]'"${nas_name}"'[[:blank:]]*$/ d'. Generally, though, it’s a worthwhile approach.

Note that your script could be simplified in many ways, including using a single sed command to update the existing entry directly instead of deleting the old entry with sed first and then appending a new one with cat.

User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement