仅当文件尚不存在时才将行附加到文件
- 2024-10-11 08:36:00
- admin 原创
- 76
问题描述:
我需要在配置文件的末尾添加以下行:
include "/configs/projectname.conf"
到名为lighttpd.conf
我正在研究如何使用它sed
来做到这一点,但我不知道如何做。
如果该行尚不存在,我该如何插入它?
解决方案 1:
保持简单就好:)
grep + echo就足够了:
grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar
-q
安静-x
匹配整行-F
模式是一个纯字符串
编辑:合并@cerin 和@thijs-wouters 的建议。
解决方案 2:
这将是一个干净、可读且可重复使用的解决方案grep
,使用echo
并仅在文件不存在时才向文件添加一行:
LINE='include "/configs/projectname.conf"'
FILE='lighttpd.conf'
grep -qF -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"
如果需要匹配整条线路,请使用grep -xqF
-s
当文件不存在时添加忽略错误,仅使用该行创建一个新文件。
解决方案 3:
尝试一下:
grep -q '^option' file && sed -i 's/^option.*/option=value/' file || echo 'option=value' >> file
解决方案 4:
使用 sed,最简单的语法:
sed \n -e '/^(option=).*/{s//value/;:a;n;ba;q}' \n -e '$aoption=value' filename
如果参数存在,这将替换它,否则将其添加到文件底部。
-i
如果您想就地编辑文件,请使用该选项。
如果您想要接受并保留空格,并且除了删除注释之外,如果该行已经存在,但被注释掉,请写下:
sed -i \n -e '/^#?(s*options*=s*).*/{s//value/;:a;n;ba;q}' \n -e '$aoption=value' filename
请注意,选项和值都不能包含斜线/
,否则您必须将其转义为/
。
要使用 bash-variables$option
和$value
,你可以写:
sed -i \n -e '/^#?(s*'${option////\/}'s*=s*).*/{s//'${value////\/}'/;:a;n;ba;q}' \n -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 \n -e '/^#?(s*'"${name}"'s*=s*).*/{s//'"${value}"'/;:a;n;ba;q}' \n -e '$a'"${name}"'='"${value}" $3
}
解释:
/^(option=).*/
`option=:匹配以和 ( )开头的行,
.*忽略 之后的所有内容
=。
(...
)括起我们稍后将重复使用的部分
`。#
/^#?(s'"${option//////}"'s=s)./:忽略行首带有的注释掉的代码。?
表示“可选”。注释将被删除,因为它位于(
...中复制的部分之外)
。s*
表示“任意数量的空格”(空格、制表符)。空格会被复制,因为它们位于(
...内)
,因此您不会丢失格式。/^(option=).*/{…}
:如果匹配一行/…/
,则执行下一条命令。执行的命令不是单个命令,而是一个块{…}
。s//…/
:搜索并替换。由于搜索词为空//
,因此它适用于最后一个匹配项,即/^(option=).*/
。s//value/: Replace the last match with everything in
(…), referenced by
1and the text
值`:a;n;ba;q
:设置标签a
,然后读取下一行n
,然后分支b
(或转到)回到标签a
,这意味着:读取所有行直到文件末尾,因此在第一个匹配之后,只需获取所有后续行而无需进一步处理。然后q
退出,因此忽略其他所有内容。$aoption=value
:在文件末尾$
附加a
文本option=value
有关更多信息sed
和命令概述请参阅我的博客:
https://marc.wäckerlin.ch/computer/stream-editor-sed-overview-and-reference
解决方案 5:
如果写入受保护的文件,@drAlberT 和 @rubo77 的答案可能不适合您,因为无法使用 sudo >>
。 那么,一个类似的简单解决方案是使用tee --append
(或者,在 MacOS 上,tee -a
):
LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF "$LINE" "$FILE" || echo "$LINE" | sudo tee --append "$FILE"
解决方案 6:
这是一个sed
版本:
sed -e '|include "/configs/projectname.conf"|h; ${x;s/incl//;{g;t};a' -e 'include "/configs/projectname.conf"' -e '}' file
如果你的字符串在变量中:
string='include "/configs/projectname.conf"'
sed -e "|$string|h; ${x;s|$string||;{g;t};a\" -e "$string" -e "}" file
解决方案 7:
如果有一天,其他人必须将此代码作为“遗留代码”来处理,那么如果您编写一个不那么深奥的代码,那个人会很感激,例如
grep -q -F 'include "/configs/projectname.conf"' lighttpd.conf
if [ $? -ne 0 ]; then
echo 'include "/configs/projectname.conf"' >> lighttpd.conf
fi
解决方案 8:
另一个 sed 解决方案是始终将其附加在最后一行并删除预先存在的行。
sed -e '$a' -e '<your-entry>' -e "/<your-entry-properly-escaped>/d"
“正确转义”意味着放置一个与您的输入匹配的正则表达式,即从您的实际输入中转义所有正则表达式控制,即在 ^$/*?+() 前面放置一个反斜杠。
这可能会在文件的最后一行失败,或者如果没有悬垂换行符,我不确定,但可以通过一些漂亮的分支来处理......
解决方案 9:
这是一个单行 sed,它可以内联完成这项工作。请注意,当变量存在时,它会保留变量的位置及其在文件中的缩进。这对于上下文通常很重要,例如当周围有注释或变量位于缩进块中时。任何基于“删除然后追加”范式的解决方案在这方面都失败了。
sed -i '/^[ ]*option=/{h;s/=.*/=value/};${x;/^$/{s//option=value/;H};x}' test.conf
使用通用的变量/值对,你可以这样写:
var=c
val='12 34' # it handles spaces nicely btw
sed -i '/^[ ]*'"$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 '/^[ ]*'"$var"'=/{h;s/=[^#]*(.*)/='"$val"'/;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
解决方案 10:
作为 awk-only 单行命令:
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
`ENDfile
ENDsponge
mv`file
对数组的两个赋值a[]
将所有输出行累积到中a
。如果主 awk 循环在中找不到,则if(!f)a[++n]=s
附加新的。option=value
`option`file
为了便于阅读,我添加了一些空格(不是很多),但整个 awk 程序中实际上只需要一个空格,即 后面的空格print
。如果file
包含# comments
它们,它们将被保留。
解决方案 11:
这是一个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 && \n 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
解决方案 12:
使用 awk
awk 'FNR==NR && /configs.*projectname.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file file
解决方案 13:
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
解决方案 14:
以下是 awk 的一行代码:
awk -v s="option=value" '/^option/{f=1;$0=s}7;END{if(!f)print s}' file
这不会对文件进行就地更改,但是您可以:
awk '...' file > tmpfile && mv tmpfile file
解决方案 15:
使用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
解决方案 16:
sed -i '1 h
1 !H
$ {
x
s/^option.*/option=value/g
t
s/$/\noption=value/
}' /etc/fdm_monitor.conf
将缓冲区中的所有文件加载到文件中,最后更改所有出现的项,如果没有发生更改,则将其添加到末尾
解决方案 17:
使用 grep 的答案是错误的。您需要添加 -x 选项来匹配整行,否则#text to add
当试图精确添加时,像 这样的行仍然会匹配text to add
。
所以正确的解决方案是这样的:
grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar
解决方案 18:
根据我的经验,几乎所有答案都有效,但并非在所有场景或操作系统中都有效。唯一适用于旧系统和新操作系统和不同操作系统的是以下内容。
如果不存在 KUBECONFIG 路径,我需要将其附加到 bashrc 文件中。所以我做的是
我假设它存在并将其删除。
使用 sed 我附加我想要的字符串。
sed -i '/KUBECONFIG=/d' ~/.bashrc
echo 'export KUBECONFIG=/etc/rancher/rke2/rke2.yaml' >> ~/.bashrc
解决方案 19:
使用 sed:它将在行尾插入。当然,您也可以像往常一样传入变量。
grep -qxF "port=9033" $light.conf
if [ $? -ne 0 ]; then
sed -i "$ a port=9033" $light.conf
else
echo "port=9033 already added"
fi
使用一行 sed
grep -qxF "port=9033" $lightconf || sed -i "$ a port=9033" $lightconf
在 root 下使用 echo可能不起作用,但可以像这样工作。但是,如果你想这样做,它不会让你自动执行操作,因为它可能会要求输入密码。
当我尝试从根目录编辑特定用户时,我遇到了问题。只需添加$username
之前的内容即可解决问题。
grep -qxF "port=9033" light.conf
if [ $? -ne 0 ]; then
sudo -u $user_name echo "port=9033" >> light.conf
else
echo "already there"
fi
解决方案 20:
尝试:
LINE='include "/configs/projectname.conf"'
sed -n "|$LINE|q;$a $LINE" lighttpd.conf >> lighttpd.conf
使用管道作为分隔符,如果$LINE
找到则退出。否则,附加$LINE
到末尾。
因为我们只在 sed 命令中读取文件,所以我认为我们总体上没有 clobber 问题(这取决于您的 shell 设置)。
解决方案 21:
我建议仅使用sed
以下解决方案:
sed -i \n -e 's#^include "/configs/projectname.conf"#include "/configs/projectname.conf"#' \n -e t \n -e '$ainclude "/configs/projectname.conf"' lighttpd.conf
s
`include "/configs/projectname.conf用其自身替换该行(
#`此处用作分隔符)
t
如果替换成功,则跳过其余命令
$a
否则跳到最后一行并附加到include "/configs/projectname.conf
其后
解决方案 22:
我详细阐述了 kev 的 grep/sed 解决方案,通过设置变量来减少重复。
在第一行设置变量(提示:$_option
应匹配该行上的所有内容直到值[包括任何分隔符,如 = 或 :])。
_file="/etc/ssmtp/ssmtp.conf" _option="mailhub=" _value="my.domain.tld" \n sh-c'\n grep -q "^$_option" "$_file" \n && sed -i "s/^$_option.*/$_option$_value/" "$_file" \n || 回显“$_option$_value”>>“$_file”\n ‘
请注意,sh -c '...'
just 具有扩大变量范围的效果,而无需export
。 (请参阅在 bash 中命令前设置环境变量对管道中的第二个命令不起作用)
解决方案 23:
您可以使用此功能来查找和搜索配置更改:
#!/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
解决方案 24:
如果您想在 Linux 终端中使用python 脚本运行此命令...
import os,sys
LINE = 'include '+ <insert_line_STRING>
FILE = <insert_file_path_STRING>
os.system('grep -qxF $"'+LINE+'" '+FILE+' || echo $"'+LINE+'" >> '+FILE)
$ 和双引号让我陷入了困境,但这个方法有效。谢谢大家
解决方案 25:
我需要编辑具有受限写权限的文件,因此需要sudo
。根据 ghostdog74 的答案并使用临时文件:
awk 'FNR==NR && /configs.*projectname.conf/{f=1;next}f==0;END{ if(!f) { print "your line"}} ' file > /tmp/file
sudo mv /tmp/file file
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件