행이 많고 행당 열 수가 가변적인 테이블이 있습니다.
각 줄에서 첫 번째 필드와 두 문자열 중 하나가 포함된 모든 필드만 인쇄하려고 합니다(이 경우 dog 및 cow라는 단어가 포함된 모든 필드가 필요합니다).
예를 들어:
A dog999 dog284 cow284 pig383 pig234 cow432 chicken432
B cow394 cow432 cow345 dog983 pig345 chicken532
C dog847 pig357 pig236 cow395 dog496
D dog392 cow237 cow749
원하는 출력:
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
지금까지 나는 awk를 사용했습니다.
awk -v OFS='\t' '{for (i = 1; i <= NF; i++) {if ($i ~ /dog/) print $1,$i; else if ($i ~ /cow/) print $1,$i} }' file.txt
그러나 이렇게 하면 각 필드에 두 문자열 중 하나가 한 줄을 차지하게 됩니다.
답변1
perl
해결 방법이 괜찮은 경우 :
$ cat ip.txt
A dog999 dog284 cow284 pig383 pig234 cow432 chicken432
B cow394 cow432 cow345 dog983 pig345 chicken532
C dog847 pig357 pig236 cow395 dog496
D dog392 cow237 cow749
$ perl -lane 'print join("\t",$F[0],grep {/cow|dog/} @F[1..$#F])' ip.txt
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
-a
입력 줄을 공백으로 분할하고@F
배열 에 저장-l
입력에서 개행 문자를 제거하고 인쇄할 때 다시 추가하세요.join
\t
인쇄할 때,$F[0],grep {/cow|dog/} @F[1..$#F]
배열의 첫 번째 요소와cow
일치하는 모든 요소 또는dog
- 또한 사용 가능합니다
perl -lape'$_=join"\t",shift(@F),grep/cow|dog/,@F'
. 여기에서는 배열의 첫 번째 요소를shift
제거하고 반환하며 , 결과를 에 할당하면 끝에 무료 옵션이 인쇄됩니다 (힌트).@F
$_
-p
스티븐 차제라스)
다음을 포함하지 않거나 cow
무시 dog
되는 줄:
perl -lane 'print join("\t",$F[0],grep {//} @F[1..$#F]) if /cow|dog/' ip.txt
답변2
거의 비슷하지만 일치하는 모든 단어에 대해 인쇄하고 싶지 않기 때문에 첫 번째 값을 추출해야 합니다. 이를 사용하여 printf
줄바꿈을 피할 수 있습니다.
awk '{printf "%s",$1
for (i=1;i<=NF;i++)
{
if ($i ~ /dog|cow/) { printf " %s",$i; }
}
print ""
}'
출력은 다음과 같습니다:
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
이는 한 줄로 축소할 수 있습니다.
awk '{printf "%s",$1; for (i=1;i<=NF;i++) { if ($i ~ /dog|cow/) { printf " %s",$i; } } print "" }'
이렇게 하면 어떤 단어와도 일치하지 않는 줄이 인쇄됩니다.
E pig sheep
출력됩니다
E
답변3
$ txr -e '(awk (:let tmp)
(:begin (set ofs "\t"))
(f (set tmp (pop f))
(ff (keep-if #/cow|dog/))
(push tmp f) (prn)))' data
A dog999 dog284 cow284 cow432
B cow394 cow432 cow345 dog983
C dog847 cow395 dog496
D dog392 cow237 cow749
분해:
:let
매크로의 절은 지역 변수를 지정합니다. 이 매크로는 "Awk Paradigm"을 구현하지만 사용하기 전에 변수를 정의해야 하는 유형 안전 언어로 구현됩니다. 따라서 및 ( POSIX Awk 와 유사)과:begin
같은 절 외에도 이 Awk는 어휘 범위 매크로로 정의된 변수도 제공합니다.:end
BEGIN
END
:let
(f (set tmp (pop f)) ...)
조건이 인 조건부 작업 절입니다f
. 레코드의 구분된 필드 목록인 경우 비어 있지 않으면( 와 같지 않음nil
) 부울 true처럼 작동합니다. 따라서 에 아무것도 없으면 작업 양식이 실행됩니다f
.(set tmp (pop f))
목록에서 첫 번째 필드를 팝하고 임시 변수에 저장합니다tmp
. 두 번째 필드가 첫 번째 필드가 되고, 세 번째 필드가 두 번째 필드가 되는 식입니다.f
레코드는 필드를 사용하여 레코드가 재구성되는 POSIX Awk와 마찬가지로 작업할 때rec
자동으로 재구성됩니다 .ofs
$0
OFS
(ff ...)
이 경우 작업별로 필드를 필터링합니다(keep-if #/regex/)
. 기본적으로f
정규식과 일치하지 않는 모든 필드를 제거합니다.ff
매크로 내부에 표시되는 연산자입니다awk
.keep-if
일반 함수입니다. 여기서는 암시적으로 카레되므로 목록 인수가 표시되지 않습니다. 조건자 함수가 필요하지만 정규 표현식은 함수 호출 가능하므로 조건자로 적합합니다.그런 다음 이전에 저장한 첫 번째 필드를 다시 필드
f
목록 에 푸시합니다(push tmp f)
.(prn)
와 동일합니다print
. 인수가 없으면 레코드와ors
개행 문자로 초기화되는 출력 레코드 구분 기호( )를 인쇄합니다.rec
의 모든 작업이 재구성되었으므로 필터링f
된 출력을 얻습니다.
보시다시피, Awk 패러다임은 기본적으로 완전합니다. 단지 다른 언어의 맥락에서 다른 종류의 일이 가능하다는 것뿐입니다. 필드가 실제로 존재하는지 확인하지 않고 작동할 수 있는 편리함은 $2 > $1
없지만 반면에 필드를 데이터 구조로 처리하기 위해 루프를 작성할 필요가 없습니다. 필드는 함수를 통해 매핑되거나 스택으로 표시될 수 있습니다.
Sundeep의 Perl 솔루션은 대략 awk
다음 매크로로 변환됩니다.
$ txr -e '(awk (t (prn `@[f 0]\t@{(keep-if #/cow|dog/ [f 1..:]) "\t"}`)))' data