在 bash 中,在 sed 和 cat 之后得到不需要的换行符 >>

In bash got unwanted newlines after sed and cat >>

我正在尝试用我的脚本替换 /etc/hosts 文件中的一些行:

#!/bin/bash

hosts_file_path="/etc/hosts"

nas_servers=( 'mynas01' 'mynas02' )

strange_string="<00>"

for nas_name in ${nas_servers[@]}; do
    printf '%ls\n' "$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 '%ls\n' "$s" >> "$hosts_file_path"
    fi
done 

它搜索例如对于

这样的行
192.168.1xx.xxx mynas01

并用 sed 命令替换该行(如果找到),但之后添加,例如至

192.169.1xx.xxx mynas01 

我必须这样做(?)因为我的 LAN 网络地址经常变化(确切地说:在每个工作日,但不总是在工作会话中),所以每次编辑 /etc/hosts文件不是很有用,即使设置像 SNMP 这样的东西(对于两台服务器)对我来说有点太多开销 - 我只想将这个脚本放在 cron 作业或 rc.local 中并避免 smblookups.

现在我的问题是:如果我这样做,在文件结束后会有更多的空换行 and/bewtween 添加的文本,我怎样才能避免这种情况并且有更短的办法吗?

到目前为止我得到的结果是 (/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

谢谢

只需使用 grep -v 从文件中删除您不喜欢的行。它比 grep 之后的 sed 更容易,就像您现在所做的那样,并且不会留下空行。

假设您有一个 /etc/hosts 如下所示的文件

192.168.111.000 mynas01
192.168.222.000 mynas01
192.168.333.000 mynas01
000.192.168.000 mynas01

你只需要做:

cat /etc/hosts | sed 's/^192\.168\./192\.169\./'

你得到

192.169.111.000 mynas01
192.169.222.000 mynas01
192.169.333.000 mynas01
000.192.168.000 mynas01

问题是您的 sed 命令不是 删除 感兴趣的行,而是将其变成 行,所以实际上你 删除了 一个旧的 NAS 条目,同时为其添加了一个新行,这会不断添加行。

改用以下 sed 命令,该命令 删除 匹配行:

sr="/${nas_name}/ d"

或者更稳健地排除误报:

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

由于使用了double-quoted字符串,所以通常必须对$个字符使用$。 shell 应该 而不是 展开。
但是,shell 留下了一些在语法上不是有效的变量引用,因此 $/ 被传递给 sed as-is.
为了更严格地将 shell 扩展部分 (double-quoted) 和 Sed 脚本 (single-quoted) 分开,您可以使用以下内容,但它更难阅读:sr='/[[:blank:]]'"${nas_name}"'[[:blank:]]*$/ d'.不过,总的来说,这是一种值得的方法。

请注意,您的脚本可以通过多种方式进行简化,包括使用单个 sed 命令直接更新现有条目,而不是先使用 sed 删除旧条目,然后再添加新条目一个 cat.