저는 Unix에 익숙하지 않고 매우 큰 CSV 파일을 작업하고 있습니다.
예는 다음과 같습니다.
ABC1,ABC2,ABC3,DDD,EEE,FFF
1,2,3,4,5,6
1,2,3,4,5,6
로 시작하는 모든 열을 추출하는 방법은 무엇입니까 ABC
?
답변1
다음 awk
프로그램이 그 트릭을 수행할 것입니다. 다음과 같은 파일에 저장하십시오 extract.awk
.
#!/bin/awk -f
BEGIN { FS=OFS=","}
FNR==1 {
for (i=1;i<=NF;i++) {
if (index($i,startstr)==1) cols[++ncol]=i;
}
}
{ for (j=1;j<=ncol;j++) printf("%s%s",$(cols[j]),j==ncol?ORS:OFS) }
그럼 전화하면 돼
~$ awk -f extract.awk -v startstr="ABC" input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,3
문자열을 찾으려는 변수의 위치를 정의합니다 startstr
.
그러면 먼저 입력 및 출력 필드 구분 기호가 로 설정됩니다 ,
.
- 첫 번째 행(헤더 행)에서는 변수에 저장된 검색 문자열로 시작하는 열 이름이 있는지 확인합니다
startstr
. 그렇다면 열 번호가cols
"인쇄할 열" 배열에 추가됩니다. - 각 행(첫 번째 행 포함)에 대해 저장된 모든 열의 값을 인쇄한
cols
다음 마지막 열인 경우 필드 구분 기호 또는 레코드 구분 기호(기본값은 줄 바꿈)를 인쇄합니다.
실제 검색 문자열에 정규식 컨텍스트에 특수 문자가 포함되어 있는 경우 index()
우리가 사용하는 함수는 정규식 기반 일치 가 아닌 문자 그대로의 문자열 일치를 수행합니다. awk
정규식 기본 검색을 사용해야 하는 경우 다음을 변경하세요.
if (index($i,startstr)==1) cols[++ncol]=i;
도착하다
if ($i ~ startstr) cols[++ncol]=i
그러나 그 안의 모든 문자는 startstr
정규식 토큰으로 해석되므로 주의하지 않으면 예기치 않은 동작이 발생할 수 있습니다. 언급하신 예의 startstr
경우 ^ABC
.
답변2
awk를 사용하여 이 작업을 수행할 수 있지만 Perl의 어레이 슬라이싱 기능 덕분에 Perl에서는 더 쉽습니다. awk에서는 동일한 결과를 얻으려면 필요한 배열을 반복해야 합니다.
#!/usr/bin/perl
use strict;
my @wanted; # array to hold the indices we want to print
while(<>) {
chomp;
# split the input line into array @F, using commas as the delimiter.
my @F = split /,/;
if ($. == 1) { # process the first line (the headers)
# if a header matches the regex, add it to @wanted
foreach my $i (0 .. $#F) {
push @wanted, $i if $F[$i] =~ m/^abc/i;
};
};
# print the columns of @F whose indices are listed in @wanted
print join(",", @F[@wanted]), "\n";
}
예를 들어 다른 이름으로 저장 abc.pl
하고 실행 가능하게 만든 chmod +x abc.pl
후 다음과 같이 실행하십시오.
$ ./abc.pl input.csv
ABC1,ABC2,ABC3
1,2,3
1,2,3
작동 원리:
- 루프는 각 필드의
foreach
일치하는 인덱스 번호 (대소문자 구분 안 함)를 배열 에 추가합니다./abc/
@wanted
- 주어진 샘플 입력 후에는 최종적으로 , 및 가
@wanted
포함됩니다 .0
1
2
@F[@wanted]
명령문에 사용된 as는 실제로print join()
(즉, 요소 및 of)와 동일합니다. 이러한 요소는 쉼표 문자로 연결되어 인쇄됩니다.@F[0,1,2]
0
1
2
@F
추가 사항:
if ($. == 1) {...}
foreach
Perl의 기능을 사용하기 위해 using 블록을 다시 작성할 수 있습니다 grep
. 전체 블록은 단 한 줄로 대체될 수 있습니다:
@wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);
어떤 사람들은 이것이 Perl 관용적이라고 말할 것입니다. 나는 동의하지 않습니다. Perl에는 foreach
and grep
(및 map
배열 join
이나 목록을 다루는 다른 많은 함수와 연산자)가 있으며 다음을 사용합니다.어느그중에는 "관용적 펄"이 있습니다.
참고: keys
인덱스 배열을 사용하려면 2010년에 출시된 v5.12 이상의 Perl 버전이 필요합니다. 이전에는 keys
해시 배열로만 작업했습니다.
또한 전체 스크립트는 다음 두 개의 문만 사용하여 한 줄로 압축할 수 있습니다.
$ perl -F, -lne '@wanted = grep($F[$_] =~ m/^abc/i, keys @F) if ($. == 1);
print join(",", @F[@wanted]);' input.csv
답변3
답변4
flds=$(< file head -n 1 | tr ',' '\n' | grep -ne '^ABC' | cut -d: -f1 | paste -sd, -)
cut -d, -f"${flds}" file
ABC1,ABC2,ABC3
1,2,3
1,2,3
이를 두 단계로 수행합니다. 먼저 헤더를 추출한 다음 헤더에서 ABC로 시작하는 필드에 대한 필드 번호를 가져옵니다.
다음으로 이 정보를 사용하여 cut 명령에 연결하여 전체 파일에서 이러한 필드를 추출합니다.