在正则表达式模式中使用 .sh 中的 $1 来替换文件中的内容

在正则表达式模式中使用 .sh 中的 $1 来替换文件中的内容

我一直在尝试但没有取得多大成功捕获两个单词之间的单词获取两个下划线之间的单词在许多其他人中...

我想在“##”之前找到换行符,这个“##”在“## baba”之后,但不是紧随其后,中间有一些文本。文件中有很多“##”,前面总是带有\ n. 参见下面的架构:

所需输出

##

## baba {could also be "foo" or "bar"}

rosa rosa rosam rosae ipsum

{append or replace the '\n' before '\n##' with -> helloworld here}


##

##

一旦找到,插入“helloworld”作为脚本的参数

我当前的脚本找到

awk -i inplace -v foo=$2 -v new=$1'\n\n' 'f&&/^##/{print new; f=0} {print} /^## baba/{f=1}' a.md

我想要两件事: 1/ 用参数 $2 (变量 foo)替换 baba,2/ 将 \n 包含在 ^## 中,使其位于上面一行。

非常感谢您的帮助


编辑:感谢 Rudic 我想出了:

sed -re "/## $1/,/^\n\n##/ {s/^## *$/$2\n\n\n&/}" a.md

MD

##


## baba

rosa rosa rosam rosae ipsum



##



##

命令行

cat a.md && echo "---------------" && ./test.sh baba remember140416sewol

但输出有 2 个缺陷,1/ 为每个匹配写入,我只想要第一个匹配,2/ 不会替换另一个换行符之前的新行:

##


## baba

rosa rosa rosam rosae ipsum

{\n <-extra new line}
remember140416sewol


##


remember140416sewol {<-- extra occurence}


##

答案1

可能是这样的:

sed '/## *baba/,/^##/ {s/^## *$/helloworld\n&/}' file

或者,如果作为参数给出,

sed "/## *$2/,/^##/ {s/^## *$/$1\n&/}" file

答案2

以下将从命令行获取模式以及替换文本,并将它们分配给awk变量patterntext

在该BEGIN块中,我修改模式以^## 在开头包含正则表达式。

然后,我使用范围表达式来触发将针对文档中的给定部分执行的代码块(以 开头的部分,## 后跟与原始 匹配的内容pattern,直到与表达式 匹配的行^##$)。

如果在该块中当前行恰好与表达式匹配^##$,我将打印hello world用户给出的字符串,并添加两个额外的换行符。

所有输入行均由最终{ print }块打印。

如果您想使用位置参数$1(对于替换文本)和$2(对于模式),请将baba下面的内容替换为$2和。同样,如果您有任何其他两个变量来保存替换文本和模式。hello world$1

awk -v pattern="baba" -v text="hello world" '
    BEGIN { pattern = "^## " pattern }
    $0 ~ pattern,/^##$/ { if (/^##$/) print text "\n\n" }
    { print }' a.md

另一种实现是从两个环境变量中获取模式和文本:

PATTERN="baba" TEXT="hello world" awk '
    BEGIN { pattern = "^## " ENVIRON["PATTERN"] }
    $0 ~ pattern,/^##$/ { if (/^##$/) print ENVIRON["TEXT"] "\n\n" }
    { print }' a.md

鉴于问题末尾的文档,这将生成

##

## baba

rosa rosa rosam rosae ipsum


hello world


##

##

与通过变量将数据传递到相关awk


作为在评论中要求,一个带有两个参数的脚本,一个模式和一个替换字符串,或者两个环境变量PATTERNSTRING

#!/bin/sh

if [ "$#" -eq 0 ]; then
    # No arguments given.
    # Take pattern and string from environment.

    pattern=${PATTERN:?missing}
    string=${STRING:?missing}
else
    # Arguments given.
    # Take pattern and string from 1st and 2nd argument.

    pattern=${1:?argument 1 (pattern) missing}
    string=${2:?argument 2 (string) missing}
fi

# Either of the two `awk` commands from above would work,
# with $pattern and $string inserted in the appropriate
# command line arguments to awk:

awk -v pattern="$pattern" -v text="$string" '
    BEGIN { pattern = "^## " pattern }
    $0 ~ pattern,/^##$/ { if (/^##$/) print text "\n\n" }
    { print }' a.md

你可以将其运行为

./script.sh 'baba' 'hello world'

或作为

export PATTERN='baba' STRING='hello world'
./script.sh

未能提供两个命令行参数或两个环境变量将导致错误消息,并且代码awk根本无法运行。

答案3

我最终使用一个非常有用的 python 脚本自己解决了这个问题,它正是我想要的:

import sys
import os
import re

topic = sys.argv[1]
pattern = "## " + topic

s = r"cat a.md | grep -n '" + pattern + "' a.md | awk -F ':' '/0/ {print$1}'"
#print(s)
pattern = re.compile("##")

stream = os.popen(s)
lineNb = int(stream.read().rstrip())

filename="a.md"
with open(filename, "r") as f:
    for _ in range(lineNb):
            next(f)
    for line_i, line in enumerate(f, 1):
        if re.search(pattern, line):
            index = line_i + lineNb - 1
            #print( "%d\n" % index )
            break

with open(filename, "r") as f:
    contents = f.readlines()
    contents.insert(index - 1, sys.argv[2] + "\n\n")

with open(filename, "w") as f:
    contents = "".join(contents)
    f.write(contents)


可能可以进一步优化,欢迎任何建议。

相关内容