첫 번째 열의 문자열이 이전 줄의 첫 번째 열에 있는 문자열과 다를 경우 이전 줄 전체를 인쇄하는 awk 프로그램을 Linux에서 작성하려고 합니다.
또 다른 접근 방식은 첫 번째 열이 동일할 때마다 일치하는 열의 마지막 행 전체를 인쇄하고 이전의 동일한 열을 삭제하는 것입니다.
나는 다음 코드를 사용했습니다.
awk 'BEGIN { FS=OFS=";" } $1==last{next} {last=$1} {print last}' test.txt
하지만 이전 행의 첫 번째 열만 인쇄하는 것 같아요. 이전 줄 전체를 인쇄하는 방법은 무엇입니까?
내 입력 파일은 test.txt
다음과 같습니다.
818522;"Joey";
817399;"john";
817399;"CCE";
817399;"smith";
817399;"Ron";
817400;
817400;
817400;
818000;"ODC";
890021;
890021;
890021;"rachel";
890021;"monica"
원하는 출력:
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021;"monica"
답변1
귀하의 설명이 출력과 일치하지 않아 약간 혼란 스럽습니다. 귀하의 설명에 따르면 예상되는 출력은 다음과 같습니다.
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021
마지막 줄이므로 어떤 줄도 인쇄하지 않으므로 첫 번째 필드는 다음 줄과 다르지 않습니다. 이것이 실제로 원하는 것이라면 다음과 같이 할 수 있습니다.
$ awk -F';' '{
if($1!=last && prevLine){ print prevLine }
{ last=$1; prevLine=$0 }
}' file
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
마지막 줄에도 예외를 추가하려면 다음을 시도해 보세요.
$ awk -F';' '{
if($1!=last && prevLine){
print prevLine;
lastPrinted=last
}
{
last=$1;
prevLine=$0
}
}
END{
if($1 != lastPrinted){ print }
}' file
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021;"monica"
last
아이디어는 매우 간단합니다. 첫 번째 필드가 정의된 변수와 다르면 prevLine
(그래서 첫 번째 줄을 인쇄하지 않음) 이전 줄( prevLine
)을 인쇄하고 이전 줄의 첫 번째 필드( last
)를 변수에 저장합니다. lastPrinted
.
그런 다음 모든 행에 대해 last
첫 번째 필드와 prevLine
현재 행을 설정합니다. 마지막으로 파일의 끝에 도달하면( END{}
) 줄의 첫 번째 필드가 지난번에 인쇄한 첫 번째 필드( )와 다른 경우 해당 줄을 인쇄합니다 lastPrinted
.
답변2
$ awk -F';' '$1 != l1 && l1 != "" { print l0 };
{l1 = $1; l0 = $0};
END {if ($1 != $l1) {print}}' test.txt
818522;"Joey";
817399;"Ron";
817400;
818000;"ODC";
890021;"monica"
이 -F';'
옵션은 awk의 입력 필드 구분 기호( FS
)를 세미콜론으로 설정합니다. awk는 각 입력 라인을 자동으로 분할 FS
하고 필드를 $1, $2, $3, ...., $n에 할당합니다.
변수 l1
sum은 첫 번째 필드( )와 전체 행( )을 l0
보유하는 데 사용됩니다 .$1
$0
대부분의 경우 awk
스크립트는 일련의 PATTERN { ACTION }
규칙입니다. PATTERN이 true로 평가되면 ACTION이 실행됩니다. PATTERN은 true 또는 false로 평가되는 모든 항목(정규식 일치, 변수 비교, 계산 등)이 될 수 있습니다. ACTION은 임의의 awk 코드 문일 수 있습니다. 이러한 규칙은 각 입력 줄에 대해 반복됩니다. PATTERN 또는 ACTION은 선택 사항일 수 있습니다. PATTERN이 누락된 경우 true로 평가된 것으로 간주되어 ACTION이 항상 실행됩니다. ACTION이 누락된 경우 기본 동작은 print
(즉, 현재 입력 줄 인쇄)입니다. 이는 매우 간단하고 단순화된 요약입니다. 자세한 내용은 awk 문서를 참조하세요(예: man awk
GNU awk를 사용하는 경우 info awk
O'Reilly도 참조).sed와 awkDale Dougherty와 Arnold Robbins의 책).
awk 스크립트의 첫 번째 줄은 현재 줄이 다음과 같은지 여부를 테스트합니다 $1
.같지 않음둘 다l1
그리고빈 문자열. 두 테스트가 모두 true이면 마지막 입력 줄을 인쇄합니다 l0
. 입력의 첫 번째 줄은 l1
항상 비어 있으므로(스크립트의 두 번째 줄은 아직 실행되지 않았으므로 아직 값이 할당되지 않았기 때문에) 아무 것도 인쇄되지 않습니다( l0
어차피 비어 있음) . , 따라서 인쇄하면 빈 줄만 출력됩니다.)
awk 스크립트의 두 번째 줄은 무조건 현재 입력 줄의 합계를 설정합니다 l1
.l0
스크립트는 각 입력 줄에 대해 이 두 줄의 코드를 반복합니다.
더 이상 입력이 없으면 기본 스크립트 루프가 종료되고 END {...}
블록이 실행됩니다. 현재 입력 줄(즉, 입력의 마지막 줄)을 인쇄합니다. 현재는 $1 != l1
리플렉션(및 일부 간단한 테스트)을 사용하는 경우에만 해당 테스트 없이도 잘 작동할 수 있습니다 END {print}
.
답변3
$ mlr --csv --fs ';' -N --ragged unsparsify then tail -n 1 -g 1 file
818522;Joey;
817399;Ron;
817400;;
818000;ODC;
890021;monica;
이는 다음을 사용합니다.밀러( mlr
)는 데이터를 제목 없는 CSV로 읽고 ;
필드 구분 기호 역할을 합니다. 입력을 통해 각 레코드는 서로 다른 수의 필드를 가질 수 있습니다.
먼저 이 작업을 사용하여 각 레코드의 존재하지 않는 필드를 null 값으로 채운 unsparsify
다음 tail
첫 번째 필드로 그룹화할 때 각 그룹의 마지막 값을 가져옵니다.
필요한 경우 출력에 인용문이 추가되거나 --quote-all
모든 필드에 인용문을 추가할 수 있습니다.
답변4
사용 datamash
:
$ datamash -t ';' -g 1 last 2 <file
-t ;
필드 구분 기호로 세미콜론을 설정합니다.
last 2
필드 2의 마지막 값을 인쇄합니다.
-g 1
예의 약어입니다 groupby 1
.
이 명령은 다음에서 가져온 것입니다.Datamash는 단 하나의 라이너를 대체합니다.. "각 그룹의 마지막 값"을 참조하십시오.