如何使用bash替换文件中除最后一个匹配之外的所有匹配?

如何使用bash替换文件中除最后一个匹配之外的所有匹配?,bash,replace,Bash,Replace,假设使用bash,配置文件如下: 参数a=AAAAA 参数b=bbbbbb param foo=第一次出现如果awk可接受,这将对param foo和param-x执行: 如果有什么不同,请告诉我 第二次编辑:为mawk用户提供解决方案: 对于长文件来说有点慢,但对于所有参数都应该有效: grep -v ^# $file | cut -f1 -d= | sort -u | sed 's/^/grep -n . '$file' | tac | grep -m1 :/;s/$/= /' | bash

假设使用bash,配置文件如下:

  • 参数a=AAAAA
  • 参数b=bbbbbb

  • param foo=第一次出现如果awk可接受,这将对param foo和param-x执行:

    如果有什么不同,请告诉我

    第二次编辑:为mawk用户提供解决方案:


    对于长文件来说有点慢,但对于所有参数都应该有效:

    grep -v ^# $file |
    cut -f1 -d= |
    sort -u |
    sed 's/^/grep -n . '$file' |
    tac |
    grep -m1 :/;s/$/= /' |
    bash |
    sed -r 's%([0-9]+):(.*)=(.*)%\1!s/^\2=/# \2=/%' |
    sed -f- $file
    

    我尚未对脚本进行全面测试,但它在第一个示例中起到了作用:

    #!/bin/bash
    input_file=/path/to/your/input/file    
    last_occurence=`nl $input_file | grep 'param-foo' | grep -v '#' | tail -1 | awk -F" " '{print $1}'`
    sed -i '/#/!s/param-foo/# param-foo/g' $input_file
    sed -i "${last_occurence}s/# param-foo/param-foo/" $input_file
    
    这是非常直接的逻辑。首先,我们得到最后一个出现的param foo,它没有被注释。 第一个sed去注释所有未注释的param foo。 第二个sed使用param foo最后一次出现的行号,并删除#字符。您可以轻松地将其包装在函数中并在循环中使用,从而提供参数列表,而不是仅提供一个。

    这可能会起作用:

    param="param-foo"
    tac input_file |sed '/#/!{/'"$param"'/{x;/./{x;s/'"$param"'/# &/;t};x;h;}}'|tac >output_file
    
    对于多个参数:

    cp input_file{,.backup}
    params=(param-{foo,bar,baz})
    tac input_file >backwards_file
    for param in "${params[@]}"; do
        sed -i '/#/!{/'"$param"'/{x;/./{x;s/'"$param"'/# &/;t};x;h;}}' backwards_file
    done
    tac backwards_file >output_file
    
    input_file
    向后旋转,使用注释
    #
    预处理除第一次出现的
    $param
    之外的所有文件,然后还原该文件

    编辑: 要从文件中提取参数,请使用以下代码:

    params=($(sed -rn '/^#/d;/^$/!s/^\s*([^=]*).*/\1/gp' input_file | sort | uniq))
    

    非常感谢。看起来像是我需要的。然而,这对我不起作用。它没有显示任何内容:(行开头的数字是真实输入文件的一部分吗?不..对不起,可能让你困惑..它们只是用来指示行号的。这是我的第一篇文章,我正在尽全力:)好的,我假设它们不是输入文件的一部分,所以我不明白为什么它不起作用。你能发一份真实文件的样本吗?你的操作系统是什么?我正在使用lubuntu 11.10,awk已安装并正在运行(通过另一个更简单的测试进行了尝试)我将编辑你的asnwerdo中的剩余信息你总是在#和实际文本之间留有空格吗?我通常这样评论,但其他人可能会有不同的评论。。因此,唯一确定的事情是有一个以“谢谢你的提示”开头的评论行!但是,在此处运行代码会导致某些行丢失:(…我编辑您的答案以向您表明我无法编辑您的答案..无论如何,只显示最后一个活动行,而删除之前的任何活动行,因此删除所有注释行。这不是预期的结果,尽管您的解决方案会导致我误读规范,对不起。我编辑了答案:现在比预期的短1行d应该能用。嗨,你的代码还在“奇怪”地工作这里:第一次出现的param foo和param-x没有被注释,但是被删除了,因此第二次出现的param foo,param foo的第一个注释也被删除了。最后,行的顺序没有得到维护,这是很重要的。抱歉:/I我重新阅读了规范并编辑了代码。它不再短也不好看,但可以工作。没关系…感谢您的输入!它工作得非常完美!除了awk部分,我可以理解它的功能(我仍然从未使用过awk,也许这就是我自己无法理解的原因)您好,非常感谢您的回答!我非常喜欢您为单个参数提供的解决方案!当然我会使用它。对于多个参数,我应该更好地表达自己:我以前不知道文件中重复的参数的名称。我将编辑我的问题以更好地澄清这一点。当然,我可以在重复p之前进行一些检查文件中的参数,并创建数组$params以传递给脚本,但如果您知道如何更优雅地执行该操作,那就太好了!Regardsy您针对单个参数的解决方案非常优秀,我已经成功地采用了它!:)您知道如何修复多个参数的解决方案以自动检测哪些是重复的参数吗?
    #!/bin/bash
    input_file=/path/to/your/input/file    
    last_occurence=`nl $input_file | grep 'param-foo' | grep -v '#' | tail -1 | awk -F" " '{print $1}'`
    sed -i '/#/!s/param-foo/# param-foo/g' $input_file
    sed -i "${last_occurence}s/# param-foo/param-foo/" $input_file
    
    param="param-foo"
    tac input_file |sed '/#/!{/'"$param"'/{x;/./{x;s/'"$param"'/# &/;t};x;h;}}'|tac >output_file
    
    cp input_file{,.backup}
    params=(param-{foo,bar,baz})
    tac input_file >backwards_file
    for param in "${params[@]}"; do
        sed -i '/#/!{/'"$param"'/{x;/./{x;s/'"$param"'/# &/;t};x;h;}}' backwards_file
    done
    tac backwards_file >output_file
    
    params=($(sed -rn '/^#/d;/^$/!s/^\s*([^=]*).*/\1/gp' input_file | sort | uniq))