패턴 (마커) 전에 다른 파일에 파일 내용을 삽입하는 방법은 무엇입니까?


32

File1 내용:

line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 

File2 내용:

line1-file2     "25"  
line2-file2     "24"  
Pointer-file2   "23"  
line4-file2     "22" 
line5-file2     "21"

perl / shell 스크립트를 실행 한 후 File2내용은 다음과 같아야합니다.

line1-file2     "25"  
line2-file2     "24" 
line1-file1      "1" 
line2-file1      "2"
line3-file1      "3" 
line4-file1      "4" 
Pointer-file2   "23" 
line4-file2     "22" 
line5-file2     "21"

즉의 내용을 붙여 File1에서을 File2"포인터"를 포함하는 줄 앞에.




나는이 이유로 폐쇄에 대해 이미 SO 질문에 투표했다.이 질문을 닫을 이유가 더 이상 없다. Btw, 문제는 SO의 품질이 훨씬 나빠서 논리는 이것을 닫지 말라고 지시합니다.
피터는 모니카 복원

답변:


33

sed 이를위한 기능이 있으며 수정을 인라인으로 수행 할 수 있습니다.

sed -i -e '/Pointer/r file1' file2

그러나 이것은 포인터 줄을 file1 위에 놓습니다 . 아래에 넣으려면 지연 라인 출력 :

sed -n -i -e '/Pointer/r file1' -e 1x -e '2,${x;p}' -e '${x;p}' file2 

8
무엇을하는지 설명해 주 -e 1x -e '2,${x;p}' -e '${x;p}'시겠습니까? 패턴 버퍼에서 물건을 교환 한 다음 인쇄한다는 것을 이해하지만 -n처음에 조용한 옵션을 추가 한 이유와 이유를 모르겠습니다 .
hdl

@ jfg956 원본 파일에서 '포인터'부분을 대체하고 삭제할 수 있습니다. 이것은 sed의 두 번째 스윕으로 알아낼 수 있지만 한 번의 실행으로 가능합니까?
Alexander Cska

17

sed또는 awk...를 사용하지 않고

먼저 패턴이있는 라인을 찾으십시오.

line=$(grep -n 'Pointer' file2 | cut -d ":" -f 1)

그런 다음 3 개의 명령을 사용하여 원하는 결과를 출력하십시오.

{ head -n $(($line-1)) file2; cat file1; tail -n +$line file2; } > new_file

이 3 번 파일에 액세스하는 단점이 file2있지만,보다 명확하게 수 sedawk솔루션입니다.


10

awk이것은 상당히 쉽습니다.
파일 앞에 줄을 삽입하십시오.

awk '/Pointer/{while(getline line<"innerfile"){print line}} //' outerfile >tmp
mv tmp outerfile

Pointer줄 뒤에 내부 파일을 인쇄 하려면 패턴 순서를 바꾸십시오 (기본 조치를 취하려면 세미콜론을 추가해야 함). line변수를 삭제할 수 있습니다 .

awk '//; /Pointer/{while(getline<"innerfile"){print}}' outerfile >tmp
mv tmp outerfile

perl아직 아무도 사용 하지 않았기 때문에

# insert file before line
perl -e 'while(<>){if($_=~/Pointer/){system("cat innerfile")};print}' outerfile

# after line
perl -e 'while(<>){print;if($_=~/Pointer/){system("cat innerfile")}}' outerfile

작동하지만 포인터를 포함하는 행이 제거되었습니다.
user1228191

마찬가지로, 어떻게 파일 2에서 파일 1의 내용을 붙여 넣으려면 AWK 사용하여 해당 "포인터"를 포함하는 줄 끝에서
user1228191

@ user1228191 첫 번째를 수정하고 두 번째를 추가했습니다.
케빈

'perl'버전이 작동하지 않는 것 같습니다. 콘솔에 system("cat innerfile")출력합니다 innerfile. 뭔가 빠졌습니까?
kaartic

awk 명령 [gawk '/ <body> / {while (getline line < "$ HOME / bin / SrunScenario.style") {print line}} //'index.html> new_index.html] 그냥 루프하고 수백만 줄을 인쇄합니다 . gawk V4.2.0 여기서 무엇을 놓치고 있습니까?
JESii

7

쉬운 직업 ed:

ed -s file1 <<IN
/Pointer/-r file2
,p
q
IN

-r file1지정된 파일에서 지정된 행 다음으로 읽습니다.이 경우 첫 번째 행이 일치하는 이전 행 Pointer입니다. 따라서 여러 줄에서 발생 file2하더라도 내용을 한 번만 삽입합니다 Pointer. 일치하는 각 줄 앞에 global 플래그를 추가하려면 다음을 입력하십시오 .

ed -s file1 <<IN
g/Pointer/-r file2
,p
q
IN

교체 ,pw당신이 현재 위치에서 파일을 편집 할 경우.


허용되는 sed답변은 대부분의 경우 작동하지만 마커가 마지막 줄에 있으면 명령이 예상대로 작동하지 않습니다 File1. 마커 뒤에 내용을 삽입합니다 .
나는 처음에 시도했다 :

sed '/Pointer/{r file1
N}' file2

이것도 잘 작동 r하지만 (사이클 끝에서 마술 처럼 ) 마커가 마지막 줄에 있으면 같은 문제가 있습니다 (마지막 N줄 뒤에 연장선 이 없습니다 ). 이를 해결하기 위해 입력에 개행을 추가 할 수 있습니다.

sed '/Pointer/{              # like the first one, but this time even if the
r file1                      # marker is on the last line in File2 it
N                            # will be on the second to last line in
}                            # the combined input so N will always work;
${                           # on the last line of input: if the line is
/^$/!{                       # not empty, it means the marker was on the last
s/\n$//                      # line in File2 so the final empty line in the
}                            # input was pulled i\n: remove the latter;
//d                          # if the line is empty, delete it
}' file2 <(printf %s\\n)

file2일치하는 각 줄 앞에 내용 을 삽입 합니다. 첫 번째 일치하는 줄 l앞에만 삽입하려면 oop를 사용하고 n파일 끝이 나올 때까지 ext 행을 당기십시오 .

sed '/Pointer/{
r file2
N
:l
$!n
$!bl
}
${
/^$/!{
s/\n$//
}
//d
}' file1 <(printf %s\\n)

이러한 sed솔루션을 사용하면 내부 편집 기능이 손실되지만 다른 파일로 리디렉션 할 수 있습니다.


6

루프를 사용하여 file2의 행을 읽으십시오. 로 시작하는 줄을 찾으면 Pointerfile1을 인쇄하십시오. 이것은 아래와 같습니다 :

#!/bin/bash
while IFS= read -r line
do
    if [[ "$line" =~ ^Pointer.*$ ]]
    then
        cat file1
    fi
    echo "$line"
done < file2

4

이 문제를 해결하는 몇 가지 방법이 sed있습니다. 한 가지 방법은 승인 된 답변에 권장되는 지연된 읽기입니다. 다음과 같이 쓸 수도 있습니다 :

sed -e '$!N;P;/\nPointer/r file1' -e D file2

... 보류 버퍼로 다른 곳에서 구현 된 룩-비어 대신에 약간의 명시 적 룩-어 헤드가 있습니다. 그러나 줄 간격을 늘리고 ead 명령을 줄 번호로 적용 하기 때문에 @don_crissti가 마지막 줄에 문제 N 있습니다 r.

당신은 그것을 둘러 볼 수 있습니다 :

echo | sed -e '$d;N;P;/\nPointer/r file1' -e D file2 -

모든 것이 표준 입력을 의미하는 sed것으로 해석 -하지는 않지만 많은 사람들이 표준 입력을 의미합니다. ( POSIX는 구현자가 표준 입력을 원한다면 표준 입력을 sed지원해야 한다고 말합니다. ?? )--

다른 방법은 추가 된 내용을 순서대로 처리하는 것입니다. ead 와 동일한 방식으로 출력 을 예약 하는 다른 명령 이 있으며 스크립트 및 스크립트 순서대로 적용합니다 . 이 하나를 사용 수반 - 그것은하지만 좀 더 참여의 할 ppend 다른 사람의 출력에 일치 의 스크립트를.rsedrsedaPointersed

sed '   /Pointer/!d                  #only operate on first match
        s/[]^$&\./*[]/\\&/g;H        #escape all metachars, Hold
        s|.*|/&/!p;//!d|p;g          #print commands, exchange
        s|.|r file1&a\\&|;q' file2|  #more commands, quit
        sed -nf - file2              #same input file

기본적으로 첫 번째 sed는 두 번째 sed스크립트를 작성하는데, 두 번째 스크립트 sed는 표준 입력 (아마도 ...)을 읽고 차례로 적용합니다. 첫 번째 sedPointer찾은 이후의 quits 입력 에 대한 첫 번째 일치에서만 작동 합니다. 그 임무는 ...

  1. s/[]^$&\./*[]/\\&/g;H
    • 모든 패턴 문자는 백 슬래시로 이스케이프 처리해야합니다. 두 번째 문자는 sed문자를 올바르게 읽을 수 있도록 모든 비트를 해석해야하기 때문입니다. 완료되면 H오래된 공간에 사본을 넣으십시오 .
  2. s|.*|/&/!p;//!d|p; x
    • 두 번째 sedp모든 입력 라인 을 찢으 라고 !말하지만 /&/방금 패턴으로 보호 된 라인을 말하십시오 . 그리고 d똑같은 것을 피하기 위해 . p두 번째에 명령을 찢은 sed다음, 저장된 사본에서 작동 x하도록 h이전 및 패턴 버퍼를 변경하십시오 .
  3. s|.|r file1&a\\&|p;q
    • 유일한 우리가 여기에서 작동 숯불 것은입니다 \newline 때문에 sed우리가 하나 앞에 추가 한 것입니다 H전에 선을 ELD을. 그래서 우리는 명령을 삽입 r file1하고 \newline 다음 a\\append 명령 과 ewline을 차례로 \n따릅니다. 나머지 H필드는 마지막 줄을 따릅니다 \n.

처음 쓰는 스크립트는 다음과 같습니다.

/Pointer-file2   "23"/!p;//!d
r file1
a\
Pointer-file2   "23"

기본적으로 두 번째 sed는 모든 줄을 인쇄하지만 첫 번째 줄 seda보류 하도록 설정합니다 . 이 특정 라인의 경우 표준 출력에 대한 지연된 쓰기 2 개가 예약됩니다 . 첫 번째는 read file1이고 두 번째는 원하는 라인의 사본입니다. 이 경우 첫 번째 sed닥터 링은 필요 하지 않지만 (백 슬래시 없음 참조) 패턴 일치가 입력으로 용도 변경 될 때마다 내가 여기서하는 방식으로 안전하게 탈출하는 것이 중요합니다.

어쨌든 몇 가지 방법이 있습니다.


2

이것은 AWK에서 매우 간단합니다.

패턴 = "포인터"전에 File1을 File2로

먼저 File1의 내용을 변수에로드하십시오.

f1="$(<File1)"

그런 다음 삽입

awk -vf1="$f1" '/Pointer/{print f1;print;next}1' file2

(또는 "포인터"뒤에 File1을 삽입하려는 경우)

awk -vf1="$f1" '/Pointer/{print;print f1;next}1' file2

2

내가 선호하는 방법 : templating .

sed 's/CHANGEME/$x/g' origfile | x="$(<file2insert)" envsubst '$x' > newfile

이는 origfile에서 발생하는 모든 CHANGEME 발생을 file2insert 의 컨텐츠로 대체 합니다. CHANGEME 의 첫 번째 항목 만 바꾸려면 sed에서 마지막 g 를 제거하십시오. .


$x두 번째 명령에만 정의 된 첫 번째 명령에서 어떻게 사용할 수 있습니까?
Totor

첫 번째 명령에서 "$ x"는 두 번째 명령에서 envsubst에 의해 평가 될 자리 표시 자일뿐입니다. sed 스크립트를 작은 따옴표로 묶으면 쉘이 $ x를 평가하지 않습니다.
nrc

2

[패턴 전에 파일 내용을 다른 파일에 삽입]

sed -i '/PATTERN/r file1' -e //N file2

[패턴 후]

sed -i '/PATTERN/r file1' file2

NPATTERN이 마지막 입력 줄과 일치하면 잘 작동하지 않습니다
Sundeep

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.