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
.