仅当字符串不存在时才将文本附加到文件的更优雅的方法?

仅当字符串不存在时才将文本附加到文件的更优雅的方法?

我想将 NoDisplay=true 附加到 .desktop 文件,但前提是该条目不存在。我按以下方式执行此操作:

grep -q 'NoDisplay=true' '/usr/share/applications/yelp.desktop' || bash -c 'echo "NoDisplay=true" >> /usr/share/applications/yelp.desktop'

我想知道是否有更短的单线可以进行相同的操作?

我在 bash 脚本中使用此命令,并且必须使用命令“bash -c”。

答案1

如果你有 GNU sed,那就相当简单了:

sed -zi '/NoDisplay=true/!s/$/\nNoDisplay=true/' file

选项-z在模式空间中一次处理整行(不建议用于大文件)。如果未找到 ( ) 设置!,则将其附加到末尾并嵌入换行符。注意:替换字符串中的-i-z\n不是标准的,因此不可移植。

答案2

这个有点短。

grep -q 'NoDisplay=true' '/usr/share/applications/yelp.desktop' || echo "NoDisplay=true" >> /usr/share/applications/yelp.desktop

还有一个专门为此 Augeas 设计的工具 ( augtool)。我还没有将它与.desktop文件一起使用。所以无法帮助您了解如何使用它。

答案3

使用sed, 基于这个答案:

sed -i "/^NoDisplay=true\$/h;\${x;/^\$/{s//NoDisplay=true/;H};x}" '/usr/share/applications/yelp.desktop'

没有转义 s 就分解$

# Store the line in the hold space if found
/^NoDisplay=true$/h

# At the end of the file
${
    # Switch to the hold space
    x
    # If it's empty
    /^$/{
        # Replace the line
        s//NoDisplay=true/
        # Store it in the hold space
        H
    }
    # Switch to the hold space
    x
}

这是可以做的awk,但因为没有就地编辑在 GNU 4.1.0 之前,您基本上会做与grep+相同的事情echo

答案4

我认为你的方法中唯一可能不优雅的事情是使用 a bash -c,这不是必需的,以及用于模式和文件名的文字字符串的冗余,这实际上使你的单行很长,并且您可以将其放入要使用的变量(可能是短名称)中,例如:

p='NoDisplay=true' f='/usr/share/applications/yelp.desktop'; grep -q "${p}" "${f}" || echo "${p}" >>"${f}"

您可以通过使用重定向来使其更加紧凑,只是为了避免指定文件名两次,从而避免使用一个变量,如下所示:

p='NoDisplay=true'; (grep -q "${p}" || echo "${p}" >&0) <>/usr/share/applications/yelp.desktop

但这是否真的优雅可能是一个偏好问题。

无论如何,尽管通过变量,但模式仍然需要指定两次。我无法想象有什么方法可以避免这种情况。

另一个使用 的变体sed可能是:

p='NoDisplay=true'; sed -n "/${p}/q;\$a${p}" <>/usr/share/applications/yelp.desktop >&0

需要 GNU sed(通常出现在 Linux 上),因为a命令后面紧跟着要附加的文本(在我们的例子中是模式的变量)。

对于 POSIX 来说sed也是如此:

p='NoDisplay=true'; sed -n "/${p}/q;\$a\\
${p}
" <>/usr/share/applications/yelp.desktop >&0

相关内容