我使用以下sed
命令替换配置文件中的一些参数:
sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf
现在我有一个问题。如果该行不存在,我想将其添加到文件的底部。
我用C程序中的popen
来调用它。我尝试使用awk
。
答案 0 :(得分:60)
试试这个:
grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
答案 1 :(得分:9)
使用sed,简单的语法:
sed \
-e '/^\(option=\).*/{s//\1value/;:a;n;ba;q}' \
-e '$aoption=value' filename
这将替换参数(如果存在),否则将其添加到文件的底部。
如果要就地编辑文件,请使用-i
选项。
如果你想接受并保留空格,除了删除评论外,如果该行已经存在,但已被注释掉,请写:
sed -i \
-e '/^#\?\(\s*option\s*=\s*\).*/{s//\1value/;:a;n;ba;q}' \
-e '$aoption=value' filename
请注意,选项和值都不得包含斜杠/
,否则您必须将其转义为\/
。
要使用bash变量$option
和$value
,您可以写:
sed -i \
-e '/^#\?\(\s*'${option//\//\\/}'\s*=\s*\).*/{s//\1'${value//\//\\/}'/;:a;n;ba;q}' \
-e '$a'${option//\//\\/}'='${value//\//\\/} filename
bash表达式${option//\//\\/}
引用斜杠,它将所有/
替换为\/
。
注意:我刚陷入困境。在bash中你可以引用"${option//\//\\/}"
,但是在busybox的sh中,这不起作用,所以你应该避免引号,至少在非bourne-shell中。
所有组合在一个bash函数中:
# call option with parameters: $1=name $2=value $3=file
function option() {
name=${1//\//\\/}
value=${2//\//\\/}
sed -i \
-e '/^#\?\(\s*'"${name}"'\s*=\s*\).*/{s//\1'"${value}"'/;:a;n;ba;q}' \
-e '$a'"${name}"'='"${value}" $3
}
<强>解释强>
/^\(option=\).*/
:以option=
和(.*
)开头的匹配行会忽略=
之后的所有内容。 \(
... \)
将我们稍后将重复使用的部分包含在\1
中。#
的代码行开始。 \?
表示“可选”。评论将被删除,因为它位于\(
... \)
中复制的部分之外。 \s*
表示“任意数量的空格”(空格,制表符)。复制空格,因为它们位于\(
... \)
内,因此您不会丢失格式。/^\(option=\).*/{…}
:如果匹配行/…/
,则执行下一个命令。要执行的命令不是单个命令,而是块{…}
。s//…/
:搜索并替换。由于搜索字词为空//
,因此它适用于最后一次匹配,即/^\(option=\).*/
。s//\1value/: Replace the last match with everything in
(...), referenced by
\ 1 and the text
value` :a;n;ba;q
:设置标签a
,然后阅读下一行n
,然后将b
(或转到)分支回标签a
,这意味着:读取文件的所有行,所以在第一次匹配后,只需获取所有后续行而无需进一步处理。然后q
guit,因此忽略其他一切。$aoption=value
:在文件$
的末尾,添加a
文字option=value
有关sed
和命令概述的更多信息,请访问我的博客:
答案 2 :(得分:4)
这是一个单行的sed,可以内联工作。请注意,会在文件存在时保留变量的位置及其缩进。这通常对于上下文很重要,例如当有变量或变量位于缩进块中时。任何基于“delete-then-append”范式的解决方案都会在此失败。
sed -i '/^[ \t]*option=/{h;s/=.*/=value/};${x;/^$/{s//option=value/;H};x}' test.conf
使用通用的变量/值对,您可以这样写:
var=c
val='12 34' # it handles spaces nicely btw
sed -i '/^[ \t]*'"$var"'=/{h;s/=.*/='"$val"'/};${x;/^$/{s//c='"$val"'/;H};x}' test.conf
最后,如果您还想保留内联注释,可以使用catch组来完成。例如。如果test.conf
包含以下内容:
a=123
# Here is "c":
c=999 # with its own comment and indent
b=234
d=567
然后运行此
var='c'
val='"yay"'
sed -i '/^[ \t]*'"$var"'=/{h;s/=[^#]*\(.*\)/='"$val"'\1/;s/'"$val"'#/'"$val"' #/};${x;/^$/{s//'"$var"'='"$val"'/;H};x}' test.conf
产生:
a=123
# Here is "c":
c="yay" # with its own comment and indent
b=234
d=567
答案 3 :(得分:3)
作为一个只有一个人的单行:
awk -v s=option=value '/^option=/{$0=s;f=1} {a[++n]=$0} END{if(!f)a[++n]=s;for(i=1;i<=n;i++)print a[i]>ARGV[1]}' file
ARGV [1]是您的输入file
。它在for
块的END
循环中打开并写入。打开file
以获取END
块中的输出,取代了对sponge
等实用程序的需求或写入临时文件,然后将mv
临时文件file
更改为a[]
数组a
的两个赋值会将所有输出行累积到if(!f)a[++n]=s
。如果主要awk循环在option=value
中找不到option
,file
会附加新的print
。
为了便于阅读,我添加了一些空格(不是很多),但是你需要在整个awk程序中只需要一个空格,即file
之后的空格。
如果# comments
包含JSONObject obj = new JSONObject();
,则会保留这些内容。
答案 4 :(得分:2)
这是awk
实施
/^option *=/ {
print "option=value"; # print this instead of the original line
done=1; # set a flag, that the line was found
next # all done for this line
}
{print} # all other lines -> print them
END { # end of file
if(done != 1) # haven't found /option=/ -> add it at the end of output
print "option=value"
}
使用
运行它awk -f update.awk < /etc/fdm_monitor.conf > /etc/fdm_monitor.conf.tmp && \
mv /etc/fdm_monitor.conf.tmp /etc/fdm_monitor.conf
或
awk -f update.awk < /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf
编辑: 作为一个单行:
awk '/^option *=/ {print "option=value";d=1;next}{print}END{if(d!=1)print "option=value"}' /etc/fdm_monitor.conf | sponge /etc/fdm_monitor.conf
答案 5 :(得分:2)
这是一个awk单行:
awk -v s="option=value" '/^option/{f=1;$0=s}7;END{if(!f)print s}' file
这不会对文件进行就地更改,但您可以:
awk '...' file > tmpfile && mv tmpfile file
答案 6 :(得分:2)
使用sed
,您可以说:
sed -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename
这将替换参数(如果存在),否则将其添加到文件的底部。
如果要就地编辑文件,请使用-i
选项:
sed -i -e '/option=/{s/.*/option=value/;:a;n;:ba;q}' -e 'aoption=value' filename
答案 7 :(得分:2)
sed -i 's/^option.*/option=value/g' /etc/fdm_monitor.conf
grep -q "option=value" /etc/fdm_monitor.conf || echo "option=value" >> /etc/fdm_monitor.conf
答案 8 :(得分:1)
sed -i '1 h
1 !H
$ {
x
s/^option.*/option=value/g
t
s/$/\
option=value/
}' /etc/fdm_monitor.conf
将所有文件加载到缓冲区中,最后更改所有出现的内容,如果没有发生更改,请添加到结尾
答案 9 :(得分:0)
我通过设置变量来详细阐述kev的grep / sed解决方案,以减少重复。
在第一行设置变量(提示:$_option
应匹配该行上的所有内容,直到值[包括任何分隔符如=或:]。)
_file="/etc/ssmtp/ssmtp.conf" _option="mailhub=" _value="my.domain.tld" \ sh -c '\ grep -q "^$_option" "$_file" \ && sed -i "s/^$_option.*/$_option$_value/" "$_file" \ || echo "$_option$_value" >> "$_file"\ '
请注意sh -c '...'
只会扩大变量的范围,而不需要export
。 (见Setting an environment variable before a command in bash not working for second command in a pipe)
答案 10 :(得分:0)
您可以使用此功能查找和搜索配置更改:
#!/bin/bash
#Find and Replace config values
find_and_replace_config () {
file=$1
var=$2
new_value=$3
awk -v var="$var" -v new_val="$new_value" 'BEGIN{FS=OFS="="}match($1, "^\\s*" var "\\s*") {$2=" " new_val}1' "$file" > output.tmp && sudo mv output.tmp $file
}
find_and_replace_config /etc/php5/apache2/php.ini max_execution_time 60