파일의 내용을 바꾸려면 정규식 패턴의 .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/ baba를 매개변수 $2(변수 foo)로 대체하고, 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변수 patternsum 에 할당합니다 text.

이 블록에서는 시작 부분에 정규식을 포함 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)


추가로 최적화하는 것이 가능할 수도 있습니다. 어떤 제안이라도 환영합니다.

관련 정보