仅当文件尚不存在时才在文件中附加一行

Ben*_*ell 135 linux terminal sed

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

include "/configs/projectname.conf"
Run Code Online (Sandbox Code Playgroud)

到一个名为的文件 lighttpd.conf

我正在考虑使用sed这个,但我无法弄清楚如何.

如果该行尚不存在,我将如何仅插入它?

drA*_*erT 246

保持简单:)

grep + echo应该足够了:

grep -qxF 'include "/configs/projectname.conf"' foo.bar || echo 'include "/configs/projectname.conf"' >> foo.bar
Run Code Online (Sandbox Code Playgroud)

编辑:纳入@cerin和@thijs-wouters建议.

注意:

对于"编辑"改变我的答案:如果你有另一种解决方案给出你自己的答案!编辑旨在澄清,格式化,更好的英语等等!不要改变别人给出的答案!(谢谢)

  • 要附加的文本在表达式中出现两次。在命令前面添加 `ADDTEXT='include "/configs/projectname.conf"'` 然后使用 `$ADDTEXT` 怎么样?文件名“foo.bar”也是如此。 (4认同)
  • 您需要添加 -x 选项以确保仅匹配整行,而不是仅匹配行的一部分。 (3认同)
  • 我会将-q开关添加到grep以抑制输出:`grep -vq ...` (2认同)
  • 仅供参考,使用 -v 和 && 看起来并不能解决问题,而 || 没有 -v 工作。 (2认同)
  • 这仅适用于非常简单的行。否则,grep会将行中的大多数非字母字符解释为模式,从而使其无法检测到文件中的行。 (2认同)
  • 请注意,使用 `-F` 似乎可以解决我的问题。 (2认同)
  • 美丽的方案.当然,这也适用于触发更复杂的表达式.我使用`echo`来触发多行heredoc的`cat`到配置文件中. (2认同)
  • 如果文件不存在,请添加`-s`来忽略错误,仅使用该行创建一个新文件。 (2认同)

rub*_*o77 69

这将是一个干净,可读和可重用的解决方案,使用grepecho仅在文件尚不存在时添加一行:

LINE='include "/configs/projectname.conf"'
FILE='lighttpd.conf'
grep -qF -- "$LINE" "$FILE" || echo "$LINE" >> "$FILE"
Run Code Online (Sandbox Code Playgroud)

  • 如果它是你需要root权限的文件:`sudo grep -qF"$ LINE""$ FILE"|| echo"$ LINE"| sudo tee -a"$ FILE"` (5认同)
  • @zsero:好点!我在 grep 命令中添加了 `--`,因此它不会再将以破折号开头的 $LINE 解释为选项。 (2认同)

Pau*_*ce. 12

这是一个sed版本:

sed -e '\|include "/configs/projectname.conf"|h; ${x;s/incl//;{g;t};a\' -e 'include "/configs/projectname.conf"' -e '}' file
Run Code Online (Sandbox Code Playgroud)

如果您的字符串在变量中:

string='include "/configs/projectname.conf"'
sed -e "\|$string|h; \${x;s|$string||;{g;t};a\\" -e "$string" -e "}" file
Run Code Online (Sandbox Code Playgroud)


ham*_*x0r 10

如果写入受保护的文件,@ drAlberT和@rubo77的答案可能不适合你,因为一个人不能sudo >>.那么,一个类似的简单解决方案就是使用tee --append:

LINE='include "/configs/projectname.conf"'
FILE=lighttpd.conf
grep -qF "$LINE" "$FILE"  || echo "$LINE" | sudo tee --append "$FILE"
Run Code Online (Sandbox Code Playgroud)


Mar*_*ura 7

如果有一天,其他人必须将此代码作为"遗留代码"来处理,那么如果您编写一个不那么开放的代码,那么该人将不胜感激,例如

grep -q -F 'include "/configs/projectname.conf"' lighttpd.conf
if [ $? -ne 0 ]; then
  echo 'include "/configs/projectname.conf"' >> lighttpd.conf
fi
Run Code Online (Sandbox Code Playgroud)

  • 感谢您的评论格雷厄姆!是的,这是正常的 shell 语法。是的,任何称职的管理员都应该理解它。但是,它的工作原理是基于 shell 中表达式评估算法的副作用。所以你可以随心所欲地称呼它,除了直截了当——这是我的原点。 (4认同)

Moo*_*tus 6

这是一个单行 sed,它执行内联工作。请注意,当变量存在时,它会保留变量的位置及其在文件中的缩进。这对于上下文通常很重要,例如当周围有注释或变量位于缩进块中时。任何基于“删除然后附加”范式的解决方案都在这方面失败了。

   sed -i '/^[ \t]*option=/{h;s/=.*/=value/};${x;/^$/{s//option=value/;H};x}' test.conf
Run Code Online (Sandbox Code Playgroud)

使用一对通用变量/值,您可以这样编写:

   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
Run Code Online (Sandbox Code Playgroud)

最后,如果您还想保留内联注释,可以使用 catch 组来实现。例如,如果test.conf包含以下内容:

a=123
# Here is "c":
  c=999 # with its own comment and indent
b=234
d=567
Run Code Online (Sandbox Code Playgroud)

然后运行这个

var='c'
val='"yay"'
sed -i '/^[ \t]*'"$var"'=/{h;s/=[^#]*\(.*\)/='"$val"'\1/;s/'"$val"'#/'"$val"' #/};${x;/^$/{s//'"$var"'='"$val"'/;H};x}' test.conf
Run Code Online (Sandbox Code Playgroud)

产生:

a=123
# Here is "c":
  c="yay" # with its own comment and indent
b=234
d=567
Run Code Online (Sandbox Code Playgroud)


Rob*_*479 5

另一个sed解决方案是始终将其附加在最后一行,并删除现有的。

sed -e '$a\' -e '<your-entry>' -e "/<your-entry-properly-escaped>/d"
Run Code Online (Sandbox Code Playgroud)

“正确转义”表示放置与您的条目匹配的正则表达式,即从实际条目中转义所有正则表达式控件,即在^ $ / *?+()前面加反斜杠。

这可能在文件的最后一行失败,或者如果没有悬挂的换行符,我不确定,但是可以通过一些漂亮的分支来解决...

  • 漂亮的单行,简短易读。非常适合更新 etc/hosts:`sed -i.bak -e '$a\' -e "$NEW_IP\t\t$HOST.domain\t$HOST" -e "/.*$HOST/d" /etc/hosts` (2认同)
  • @Robin479该死的,`a`pend必须在`d`elete之前执行:`sed -i -e '$a&lt;entry&gt;' -e '/&lt;entry&gt;/d'`。这与您原来的答案几乎相同。 (2认同)