在 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
.
我正在尝试用我的脚本替换 /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
.