다운스트림 프로그램에서 처리할 탭으로 구분된 대용량(~900MB) 텍스트 파일이 있습니다. 누락된 값이 있는 행을 삭제해야 합니다. 각 행에는 올바른 수의 열이 있습니다(따라서 누락된 값은 탭 2개에 해당함).
참고: 내 실제 데이터에는 약 200만 개의 행과 80~300개의 열이 있습니다. 가능한 문자에는 az AZ 0-9 -(하이픈) _(밑줄) 및 탭(구분)이 포함됩니다. 파일에는 공백이나 특수 문자가 없습니다.
저는 이런 종류의 스크립팅을 처음 접했기 때문에 제공된 코드에 대한 설명을 주시면 매우 감사하겠습니다. 나는 일반적으로 R을 사용하지만 내 파일 크기가 R의 데이터 조작 기능을 초과했습니다.
터미널(또는 쉘 스크립트)에서 누락된 값(예: using)이 있는 파일의 줄을 제거하려면 어떻게 해야 합니까 sed
?
입력 파일 예:
Col1 Col2 Col3
A B C
D F
G H I
J K
출력 파일 예:
Col1 Col2 Col3
A B C
G H I
답변1
그리고 awk
:
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' file
실제로는예그렇게 간단합니다.
awk
\t
플래그로 지정된 필드 구분자 탭에서 입력을 분할합니다-F
. 콘텐츠 필드에 공백이 없는 경우에도 이 옵션을 생략할 수 있습니다.$1!=""&&...
조건입니다. 이 조건이 true이면awk
해당 행을 인쇄하십시오. 을 쓸 수도 있지만'$1!=""&&$2!=""&&$3!=""{print}'
필수는 아닙니다. 아무 작업도 수행되지 않으면 awks의 기본 동작은 해당 줄을 인쇄하는 것입니다. 여기에서 fields$1
및 all$2
이$3
비어 있지 않은 경우, 즉 처음 3개의 필드에 값이 있는 경우 조건이 true입니다 .
다른 파일에 쓰려면 다음 명령을 사용하십시오.
awk -F"\t" '$1!=""&&$2!=""&&$3!=""' input_file >output_file
편집하다awk
: 정의되지 않은 열 수의 경우 행의 모든 필드를 확인하는 이 명령을 사용할 수 있습니다 .
awk -F"\t" '{for(i=1;i<=NF;i++){if($i==""){next}}}1' file
답변2
...다음 중 하나를 수행하려면 먼저 다음을 수행해야 합니다...
t=$(printf \\t) ### because it's hard to demo CTRL+V TAB
...지금은 POSIX를 사용하고 있습니다 grep
...
grep -Ev "^$t+|$t($t|$)" <in >out
grep
패턴과 일치하지 않는 행을 선택합니다.|
또는^
줄 머리글 탭, 두 개의 연속 탭 또는 $
줄 끝 탭을 나타내는 메타 문자 - 내가 아는 한 이것이 가능한 유일한 실패 사례입니다.
-v
음극 스위치가 없으면 다음과 같을 수 있습니다.
grep -E "([^$t]+$t){2}[^$t]" <in >out
{
... 탭 문자 뒤에 탭 문자가 오는 문자 클래스가 아닌 문자 클래스에서 하나 이상의 문자로 구성된 패턴 그룹의 발생 횟수를 지정합니다 .}
(
)
+
[
]
^
...또는 POSIX를 사용하세요 sed
...
sed -ne"s/[^$t][^$t]*/&/3p" <in >out
...또는...
sed -ne"s/[^$t]\{1,\}/&/3p" <in >out
...또는 GNU나 BSD sed
시스템을 사용하세요...
sed -Ene"s/[^$t]+/&/3p" <in >out
...기본적으로 ot는 최소한 하나 의 탭이 아닌 문자 로 구성된 가능한 가장 긴 시퀀스의 줄에서 세 번째 항목을 대체 할 수 없는 한 줄을 인쇄하지 sed
않습니다 .-n
s///
&
[^
]
(이식성을 위해 리터럴 탭을 사용하는 것이 선호됩니다. 이 답변의 원래 버전은 \
백슬래시 이스케이프를 사용했습니다.아니요도움이 되는. 문자 클래스에서 백슬래시 이스케이프를 사용하면 \
코드 적용 가능성이 확실히 제한됩니다. )[
]
답변3
필드에 공백이 포함될 수 없는 경우 빈 필드는 첫 번째 문자( ^\t
)인 탭, 마지막 문자( \t$
)인 탭 또는 두 개의 연속 탭 문자( \t\t
)를 의미합니다. 따라서 다음 중 하나가 포함된 행을 필터링할 수 있습니다.
grep -Ev $'^\t|\t\t|\t$' file
공백이 있으면 상황이 더 복잡해집니다. 필드가 공백으로 시작될 수 있는 경우 다음을 사용하십시오(공백만 있는 필드는 비어 있는 것으로 간주함).
grep -Pv '\t\s*(\t|$)|\t$|^\t' file
이 변경 사항은 탭 문자, 0개 이상의 공백, 다른 탭 문자 또는 줄 끝과 일치하는 줄을 필터링합니다.
마지막 필드에 공백만 포함된 경우에도 실패합니다. 이를 방지하려면 perl
및 -F
옵션을 사용하여 -a
입력을 배열로 분할하고 @F
필드 중 하나가 비어 있지 않으면 인쇄하도록 지시합니다( /^$/
).
perl -F'\t' -lane 'print unless grep{/^$/} @F' file
답변4
다음과 같이 시도해 볼 수 있습니다.
grep "^[a-zA-Z0-9]\+[[:space:]][a-zA-Z0-9]\+[[:space:]][a-zA-Z0-9]\+$" input_file > output_file
목적 grep
은 하나 이상의 파일에서 주어진 패턴과 일치하는 문자열을 찾는 것입니다. 여기서 패턴은 [a-zA-Z0-9]\+
하나 이상의 영숫자 문자와 그 뒤에 공백 또는 탭 문자가 오는 것과 일치합니다. 줄의 시작 부분과 일치하고 ^
, 반면은 $
줄의 끝을 나타냅니다. 열에 다른 문자가 사용되는 경우 위의 문자 클래스에 추가해야 합니다. 마지막으로 >
일치하는 출력이 출력 파일로 리디렉션됩니다.
또한 잠재적인 함정과 대체 솔루션에 대해서는 아래 @terdon의 의견을 확인하세요. Linux/Unix 환경에서 작업하는 경우 그 유용성은 grep
이 특정 솔루션을 훨씬 뛰어넘습니다.