file1의 M 줄을 file2의 N 줄로 바꿉니다.

file1의 M 줄을 file2의 N 줄로 바꿉니다.

Let M=3and . 라인 입력을 라인 입력 으로 바꾸고 N=4싶습니다 . 다음을 사용하여 문자열을 바꿀 수 있습니다 .Mfile1Nfile2sed

sed -i '3s/.*/stringToReplace/' file1

나는 이것을 사용하여 awk라인을 얻을 수 있습니다Nfile2

awk 'NR==4' "file2"

이 두 가지를 어떻게 결합할 수 있나요? 내가 시도하면

sed -i '3s/.*/{awk 'NR==4' "file2"}/' file1

그런 다음 Mline을 문자 그대로의 의미로 바꿉니다 {awk 'NR==4' "file2"}.

답변1

임의의 입력을 처리하기 위해 이를 올바르게 수행하는 방법에는 여러 가지가 있습니다.
GNU sed와 다음을 지원하는 시스템을 사용하세요 /dev/stdin.

sed -n "${n}{p;q;}" file2 | sed -e "$m{r/dev/stdin" -e 'd;p;}' file1

또는 약간 더 짧습니다 1 :

sed $n'!d;q' file2 | sed -e $m'{r /dev/stdin' -e 'd;p;}' file1

sed프로세스 교체를 지원하는 쉘을 사용하십시오.

sed '1h;1d;'$((m+1))'x' <(sed ${n}'!d;q' file2) file1

다음과 같이 쓸 수도 있습니다.

sed ${n}'!d;q' file2 | sed '1h;1d;'$((m+1))'x' - file1

기본적으로 한 번의 sed호출은 행을 추출한 n다음 file2다른 호출 에서 첫 번째 피연산자로 읽습니다 sed. 이를 보유 버퍼에 저장하고 삭제한 다음 두 번째 피연산자의 내용을 읽습니다. 즉 file1, 교환할 때 라인에서 버퍼 m+1(입력 결합)).

sed다음을 통해 스크립트 파일 읽기를 지원하는 사람:-fstdin

sed ${n}'!d;i\
'${m}'c\\
s/\\/&&/g
q' file2 | sed -f - file1

여기서 첫 번째는 sed행을 다음 과 같은 스크립트 파일 n로 바꿉니다.file2

${m}c\
line_n_content_here_with_any_backslash_escaped

그런 다음 두 번째 항목의 sed처리 에 사용됩니다 file1(예:해당 줄을 m다음 텍스트로 바꾸세요...). any 를 사용 a\하거나 텍스트를 추가할 때처럼 원본 텍스트에 있는 모든 백슬래시(포함된 줄바꿈도 포함하지만 여기에는 하나만 있음)를 이스케이프해야 합니다 i\.c\

<backslash> characters in text shall be removed, and the following character shall be treated literally.

어떤 경우에도 sed항상 인기 있는 s대체 명령을 사용할 수 있습니다.sed삽입된 대체 문자열이 모든 예약 문자를 이스케이프하는지 확인하세요.- 이 특별한 경우에는 단 한 줄입니다.

line=$(sed ${m}'!d;s|[\/&]|\\&|g;q' file2)

그런 다음 다음을 교체하십시오.

sed ${m}'s/.*/'"$line"'/' file1

대규모 입력 파일의 경우 다음을 실행할 수 있습니다.

{ head -n $((m-1)); { head -n $((n-1)) >/dev/null; head -n 1; } <file2; head -n 1 >/dev/null; cat; } <file1

이는 다음과 같은 작업을 수행합니다.

print (m-1) lines from file1
discard (n-1) lines from file2
print n-th line from file2
discard m-th line from file1
print the remaining lines from file1

어떤 head사람들은 멍청하고 어떻게 해야 할지 모르 더라도표준 준수따라서 이것이 모든 설정에서 작동하는 것은 아니지만... 작동하는 경우에는 sed속도 측면에서 더 뛰어납니다.awk


1: 일부 쉘의 경우 이것이 작동하려면 히스토리 확장을 비활성화해야 할 수도 있습니다 !...
또한 양의 정수여야 하기 때문에 여기서 인용할 필요는 없습니다 $n.$m

답변2

이 시도:

$ cat f1
foo
bar
xyz
baz
temp
good
$ cat f2
1
2
3
4
5
6

$ awk -v m=3 -v n=4 'NR==FNR{if(FNR==n) s=$0; next} FNR==m{$0=s} 1' f2 f1
foo
bar
4
baz
temp
good
  • NR==FNR첫 번째 파일이 처리 중인 경우에만 참
  • if(FNR==n) s=$0n번째 줄이면 변수에 저장
  • next이렇게 하면 첫 번째 파일이 처리되는 동안 나머지 코드는 실행되지 않습니다.
  • FNR==m{$0=s}두 번째 파일 매개변수의 m번째 라인인 경우 교체합니다.
  • 1수정 사항을 포함하여 입력 기록을 인쇄합니다.
  • 파일 입력 매개변수의 순서에 주의하세요.

if(FNR==n){s=$0;nextfile}n번째 라인 이후의 라인 처리를 피하기 위해 사용될 수 있습니다.

~에서GNU awk 매뉴얼- 감사합니다 @iruvar

참고: nextfile은 수년 동안 일반적인 확장 기능이었습니다. 2012년 9월 POSIX 표준에 통합되었습니다. 오스틴 그룹 웹사이트를 참조하세요.

답변3

짧은sed방법:

샘플 파일 f1:

f1 line1
f1 line2
f1 line3
f1 line4
f1 line5

샘플 파일 f2:

ID1,value12,value13
ID1,value22,value23
ID1,value32,value33
ID2,/value42/,~value43~
ID3,value52,value53

일하다:

sed '3 s/.*/'"$(sed -n '4{ s/\//\\\//g;p;}' f2)"'/;' f1

산출:

f1 line1
f1 line2
ID2,/value42/,~value43~
f1 line4
f1 line5

답변4

awk와 sed를 섞지 마세요. 완전한 awk 솔루션을 사용할 수 있습니다

파일 1:

 file1 1
 file1 2
 file1 3
 file1 4

파일 2:

 file2 1
 file2 2
 file2 3
 file2 4


 awk -v m=3 -v n=4 'NR == FNR { filea[FNR]=$0 } FNR != NR { fileb[FNR]=$0 } END { for (i=1;i<=FNR;i++) { if ( i == m ) { print fileb[n] } else { print filea[i] } } } ' file1 file2

분할:

 NR == FNR { 
            filea[FNR]=$0 
           }
 FNR != NR { 
            fileb[FNR]=$0 
           }
 END { 
       for (i=1;i<=FNR;i++) { 
                               if ( i == m ) { 
                                         print fileb[n] 
                                             } 
                               else { 
                                          print filea[i] 
                                    } 
                            } 
      } 

NR과 FNR을 비교하여 file1과 file2의 레코드를 결정합니다(NR=FNR인 경우 첫 번째 파일에 있음을 알 수 있음). file1의 레코드로 filea 배열을 설정하고 file2의 레코드로 fileb 배열을 설정했습니다. 그런 다음 filea 배열의 모든 레코드를 반복하고 전달된 매개변수 m이 3이 아닌 경우에만 내용을 인쇄합니다. 그렇다면 전달된 매개변수 n에 의해 결정된 배열 fileb의 첨자를 인쇄합니다.

관련 정보