나는 별 성공 없이 노력해왔어두 단어 사이의 단어 캡처그리고두 개의 밑줄 사이에 있는 단어 찾기다른 많은 것 중에서 ...
"##" 앞의 개행 문자를 찾고 싶습니다. 이 "##"은 "## 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
변수 pattern
sum 에 할당합니다 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
:
~처럼댓글로 물어보세요, 패턴과 대체 문자열이라는 두 개의 매개변수를 사용하는 스크립트,또는두 개의 환경 변수 PATTERN
및 STRING
:
#!/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)
추가로 최적화하는 것이 가능할 수도 있습니다. 어떤 제안이라도 환영합니다.