检查文件是否包含 bash 中的多行字符串

Check if a file contains a multi-line string in bash

背景

我正在编写一个函数来附加到我的 $HOME 目录中名为 .bash.local 的文件。

➡️ .bash.local 来自 .bash_profile

但是,我想有条件地附加到 .bash.local 当且仅当 文件 已经包含内容$BASH_CONFIGS.

要记住的事情

我选择的操作系统是 MacOS Mojave,因此某些版本的命令行应用程序会有所不同(例如 Mac 上的 grepBSD grep 而不是 GNU grep).

⚠️ append_to_bash_local()

append_to_bash_local() {
    local LOCAL_BASH_CONFIG_FILE="$HOME"/.bash.local

    declare -r BASH_CONFIGS="
# TOOL_NAME - TOOL_DESCRIPTION.
# Add tool configurations here
"

    # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    # If needed, add the necessary configs in the
    # local shell configuration file.

    if ! grep "^$BASH_CONFIGS" < "$LOCAL_BASH_CONFIG_FILE" &> /dev/null; then
        # this block never runs, even if the contents of $BASH_CONFIG
        # are NOT present in $HOME/.bash.local
    fi

}

你很接近。无论如何,小修复:

  • 使用零分隔 grep -Z 来匹配带有换行符的模式。如果你想到它,它有点 hacky,但每次都有效。
  • 使用 -q grep 使其静音。
  • 并且不要将文件输入标准输入到 grep,只需告诉 grep 文件名即可。
  • 检查文件是否存在

append_to_bash_local() {
     local LOCAL_BASH_CONFIG_FILE="$HOME"/.bash.local
     declare -r BASH_CONFIGS="
# TOOL_NAME - TOOL_DESCRIPTION.
# Add tool configurations here
"

if [[ "$(uname)" == "Linux" ]]; then
    if
           # if a file does not exists
           [ ! -e "$LOCAL_BASH_CONFIG_FILE" ] ||
           # if it doesn't have the content of BASH_CONFIGS
           ! grep -q -z "$BASH_CONFIGS" "$LOCAL_BASH_CONFIG_FILE"; then
        echo appending
        printf '%s\n' "$BASH_CONFIGS" >> "$LOCAL_BASH_CONFIG_FILE"
    else
        echo not appending
    fi

elif [[ "$(uname)" == "Darwin" ]]; then
    if 
            [ ! -e "$LOCAL_BASH_CONFIG_FILE" ] || 
            ! grep -q "$(<<<"$BASH_CONFIGS" tr '\n' '')" < <(
                less "$LOCAL_BASH_CONFIG_FILE" | tr '\n' ''
            ); then
        echo appending
        printf '%s\n' "$BASH_CONFIGS" >> "$LOCAL_BASH_CONFIG_FILE"
    else
       echo not appending
    fi
fi

}

@kamil-cuk 的帮助下,我能够创建 append_to_bash_local() 的改进版本。

⚠️ 请注意,因为我在 MacOS Mojave 并且默认安装了 BSD-grepBSD-sedGNU-grepGNU-sed 都没有安装, 使用 ASCII NUL 字符 截断换行符,我被迫寻找不同的解决方案。值得庆幸的是,@kamil-cuk 使用 tr 有一个 hacky 解决方案。

下面是append_to_bash_local()的改进版本。

⚠️append_to_bash_local()

  1. 首先检查文件是否不存在 [ ! -e "$LOCAL_BASH_CONFIG_FILE" ].
  2. 其次,使用-qgrep使其静音。
    • ➡️确保在grep -q前面放一个!(不是)以确保输出的状态是反转的,因为我们正在检查文件不包含$BASH_CONFIGS.
    • 的内容
  3. 最后,使用 "$(<<<"$BASH_CONFIGS" tr '\n' '')" < <(less "$LOCAL_BASH_CONFIG_FILE" | tr '\n' '') 以便 $BASH_CONFIGS 和 [] 中使用 ASCII NUL 字符 截断换行符=28=].

    append_to_bash_local() {
    
        local LOCAL_BASH_CONFIG_FILE="$HOME"/.bash.local
    
        declare -r BASH_CONFIGS="
        # TOOL_NAME - TOOL_DESCRIPTION.
        # Add tool configurations here
        "
    
        # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    
        # If needed, add the necessary configs in the
        # local shell configuration file.
    
        if [ ! -e "$LOCAL_BASH_CONFIG_FILE" ] || ! grep -q "$(<<<"$BASH_CONFIGS" tr '\n' '')" < <(less "$LOCAL_BASH_CONFIG_FILE" | tr '\n' ''); then
            printf '%s\n' "$BASH_CONFIGS" >> "$LOCAL_BASH_CONFIG_FILE"
        fi
    
    }