我有一个smb.conf
ini文件,只要使用某个GUI工具进行编辑就会覆盖该文件,从而消除了自定义设置。这意味着我需要一个cron作业来确保文件中的一个特定部分包含某个option=value
对,如果它不存在则将其插入该部分的末尾。
示例
确保hosts deny=192.168.23.
部分中存在[myshare]
:
[global]
printcap name = cups
winbind enum groups = yes
security = user
[myshare]
path=/mnt/myshare
browseable=yes
enable recycle bin=no
writeable=yes
hosts deny=192.168.23.
[Another Share]
invalid users=nobody,nobody
valid users=nobody,nobody
path=/mnt/share2
browseable=no
使用awk的长篇解决方案
经过很长一段时间与sed挣扎,我得出结论,这可能不适合这项工作。所以我搬到了awk并想出了这个:
#!/bin/sh
file="smb.conf"
tmp="smb.conf.tmp"
section="myshare"
opt="hosts deny=192.168.23."
awk '
BEGIN {
this_section=0;
opt_found=0;
}
# Match the line where our section begins
/^[ \t]*\['"$section"'\][ \t]*$/ {
this_section=1;
print $0;
next;
}
# Match lines containing our option
this_section == 1 && /^[ \t]*'"$opt"'[ \t]*$/ {
opt_found=1;
}
# Match the following section heading
this_section == 1 && /^[ \t]*\[.*$/ {
this_section=0;
if (opt_found != 1) {
print "\t'"$opt"'";
}
}
# Print every line
{ print $0; }
END {
# In case our section is the very last in the file
if (this_section == 1 && opt_found != 1) {
print "\t'"$opt"'";
}
}
' $file > $tmp
# Overwrite $file only if $tmp is different
diff -q $file $tmp > /dev/null 2>&1
if [ $? -ne 0 ]; then
mv $tmp $file
# reload smb.conf here
else
rm $tmp
fi
我不禁觉得这是一个很长的脚本来完成一个简单的任务。是否有更高效/更优雅的方法使用sed和awk等基本shell工具在ini文件中插入属性?
答案 0 :(得分:1)
考虑使用Python 3的configparser
:
#!/usr/bin/python3
import sys
from configparser import SafeConfigParser
cfg = SafeConfigParser()
cfg.read(sys.argv[1])
cfg['myshare']['hosts deny'] = '192.168.23.';
with open(sys.argv[1], 'w') as f:
cfg.write(f)
被称为./filename.py smb.conf
(即,第一个参数是要更改的文件)。
请注意,此处不会保留注释。但是,由于GUI会覆盖配置并且不保留自定义选项,因此我怀疑注释已经被破坏,并且这不是您的担忧。
答案 1 :(得分:0)
未经测试,应该可以正常工作
awk -vT="hosts deny=192.168.23" 'x&&$0~T{x=0}x&&/^ *\[[^]]+\]/{print "\t\t"T;x=0}
/^ *\[myshare\]/{x++}1' file
答案 2 :(得分:0)
这个解决方案有点尴尬。它使用INI节头作为记录分隔符。这意味着在第一个标题之前有一个空记录,所以当我们匹配我们感兴趣的标题时,我们必须阅读 next 记录来处理INI部分。此外,还有一些printf
命令,因为记录仍包含前导和尾随换行符。
awk -v RS='[[][^]]+[]]' -v str="hosts deny=192.168.23." '
{printf "%s", $0; printf "%s", RT}
RT == "[myshare]" {
getline
printf "%s", $0
if (index($0, str) == 0) print str
printf "%s", RT
}
' smb.conf
RS
是包含将文本拆分为记录的正则表达式的awk变量
RT
是包含当前记录分隔符的实际文本的awk变量。
答案 3 :(得分:0)
使用GNU awk进行几个扩展:
$ cat tst.awk
index($0,str) { found = 1 }
match($0,/^\s*\[([^]]+).*/,a) {
if ( (name == tgt) && !found ) { print indent str }
name = a[1]
found = 0
}
{ print; indent=gensub(/\S.*/,"","") }
$ awk -v tgt="myshare" -v str="hosts deny=192.168.23." -f tst.awk file
[global]
printcap name = cups
winbind enum groups = yes
security = user
[myshare]
path=/mnt/myshare
browseable=yes
enable recycle bin=no
writeable=yes
hosts deny=192.168.23.
[Another Share]
invalid users=nobody,nobody
valid users=nobody,nobody
path=/mnt/share2
browseable=no
$ awk -v tgt="myshare" -v str="fluffy bunny" -f tst.awk file
[global]
printcap name = cups
winbind enum groups = yes
security = user
[myshare]
path=/mnt/myshare
browseable=yes
enable recycle bin=no
writeable=yes
hosts deny=192.168.23.
fluffy bunny
[Another Share]
invalid users=nobody,nobody
valid users=nobody,nobody
path=/mnt/share2
browseable=no