Let M=3
and . 라인 입력을 라인 입력 으로 바꾸고 N=4
싶습니다 . 다음을 사용하여 문자열을 바꿀 수 있습니다 .M
file1
N
file2
sed
sed -i '3s/.*/stringToReplace/' file1
나는 이것을 사용하여 awk
라인을 얻을 수 있습니다N
file2
awk 'NR==4' "file2"
이 두 가지를 어떻게 결합할 수 있나요? 내가 시도하면
sed -i '3s/.*/{awk 'NR==4' "file2"}/' file1
그런 다음 M
line을 문자 그대로의 의미로 바꿉니다 {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
다음을 통해 스크립트 파일 읽기를 지원하는 사람:-f
stdin
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=$0
n번째 줄이면 변수에 저장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의 첨자를 인쇄합니다.