我需要在配置文件的末尾添加以下一行:

include "/configs/projectname.conf"

到一个名为lighttpd.conf的文件

我正在研究使用sed来做到这一点,但我不知道如何。

我怎么能只插入它,如果行已经不存在?


当前回答

作为awk专用的一行代码:

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]是你的输入文件。它被打开并写入end块的for循环中。在END块中打开文件进行输出,取代了像海绵或写入临时文件,然后将临时文件移动到文件等实用程序的需要。

对数组a[]的两次赋值将所有输出行累加到a中。if(!f)a[++n]=s如果主awk循环在文件中找不到option,则追加新的option=value。

为了可读性,我添加了一些空格(不是很多),但在整个awk程序中只需要一个空格,即打印后的空格。 如果文件包含#注释,它们将被保留。

其他回答

下面是awk的一行代码:

 awk -v s="option=value" '/^option/{f=1;$0=s}7;END{if(!f)print s}' file

这不会对文件进行就地更改,但是您可以:

awk '...' file > tmpfile && mv tmpfile file

试试这个:

grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file

使用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中,这行不通,所以你应该避免使用引号,至少在非boure -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=\).*/: Match lines that start with option= and (.*) ignore everything after the =. The \(…\) encloses the part we will reuse as \1later. /^#?(\s*'"${option//////}"'\s*=\s*).*/: Ignore commented out code with # at the begin of line. \? means «optional». The comment will be removed, because it is outside of the copied part in \(…\). \s* means «any number of white spaces» (space, tabulator). White spaces are copied, since they are within \(…\), so you do not lose formatting. /^\(option=\).*/{…}: If matches a line /…/, then execute the next command. Command to execute is not a single command, but a block {…}. s//…/: Search and replace. Since the search term is empty //, it applies to the last match, which was /^\(option=\).*/. s//\1value/: Replace the last match with everything in (…), referenced by \1and the textvalue` :a;n;ba;q: Set label a, then read next line n, then branch b (or goto) back to label a, that means: read all lines up to the end of file, so after the first match, just fetch all following lines without further processing. Then q quit and therefore ignore everything else. $aoption=value: At the end of file $, append a the text option=value

关于sed和命令概述的更多信息请参阅我的博客:

https://marc.wackerlin.ch/computer/stream-editor-sed-overview-and-reference

你可以使用这个函数来查找和搜索配置更改:

#!/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
 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