탭으로 구분된 값을 찾기 위해 "\t"를 사용하면 어떤 문제가 있나요?

탭으로 구분된 값을 찾기 위해 "\t"를 사용하면 어떤 문제가 있나요?

4개의 값(탭으로 구분된 값)이 포함된 .tsv 파일이 있습니다. 따라서 행당 세 개의 탭만 있어야 하며 각 탭 주위에는 다음과 같은 텍스트가 있어야 합니다.

value   value2  value3  value4

그런데 일부 행이 깨진 것 같습니다(탭이 3개 이상 있음). 이 줄을 찾아야 해요.


나는 다음 grep 패턴을 생각해 냈습니다.

grep -v "^[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+$"

내 생각:

  • 첫 번째 ^는 시작 부분과 일치합니다.
  • [^\t]+는 여러 "탭 없음"과 일치합니다.
  • \t는 단일 탭 문자와 일치합니다.
  • $ 경기 종료

그런 다음 올바른 순서로 올바른 횟수만큼 넣습니다. 이는 올바른 줄과 일치해야 합니다. 그래서 -v 옵션을 통해 복원하여 잘못된 줄을 얻었습니다.

그러나 -v 옵션을 사용하면 파일의 모든 줄과 탭 없이 시도한 임의의 텍스트와 일치합니다.

내 실수가 무엇입니까?

편집: 저는 데비안과 bash를 사용하고 있습니다.

답변1

보시다시피 \t기본 정규식에는 특별한 것이 없으며 grep기본적으로 BRE가 사용됩니다. grepLinux에서 기본적으로 -PPerl 호환 정규 표현식이 있는 GNU를 사용하면 \t탭 문자를 사용할 수 있습니다.

그러나 원하는 것을 달성하는 것이 훨씬 쉽습니다 awk. 입력 필드 구분 기호를 탭( -F '\t')으로 설정하고 NF필드 수( )가 3이 아닌 행을 인쇄하면 됩니다.

awk -F'\t' 'NF!=3' file

file그러면 3개보다 많거나 적은 필드를 포함하는 모든 줄이 인쇄됩니다 . 3개 이상의 필드로 제한하려면 다음을 사용하십시오.

awk -F'\t' 'NF>3' file

답변2

grep -v "^[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+$"

여기서 grep은 해당 -E옵션을 제공하지 않으므로 기본 정규 표현식(BRE)을 사용합니다. 확장 정규식(ERE)과 달리 +BRE는 특별하지 않으며 자체적으로 일치합니다. 또한 표준 정규식에서 백슬래시는 대괄호 그룹 내에서 특별하지 않으므로 [\t]백슬래시 또는 문자와 일치 t하며 [^\t]그 이외의 모든 것과 일치합니다.

대괄호 그룹 외부에서는 \t표준에서 일치하는 항목을 지정하지 않으며 이는 실제로 구현마다 다릅니다. 예를 들어 GNU의 경우 grep와 일치 t하고 ast-open의 경우 grepTAB 문자와 일치합니다.

표준 정규식에서 탭 문자를 일치시키려면 리터럴 탭 문자를 전달해야 합니다. grep예를 들어 $'...'많은 셸에서 지원하는 인용 형식을 사용합니다. (이것은 아직 표준이 아닙니다. printf탭 문자를 얻으려면 표준 쉘에서 사용해야 합니다 .)

따라서 탭 문자 로 grep $'a\tb'찾아서 구분하고, 또는 또는 하나 이상의 탭 문자로 찾아서 구분합니다 .abgrep $'a\t\t*b'grep $'a\t\\{1,\\}b'grep -E $'a\t+b'ab

답변3

좋아, 그래서 문제를 알아냈어. 사용할 수 없습니다\티grep에서는 이렇게 됩니다. 일반 문자에만 일치합니다..

탭 문자를 일치시키는 방법에 대한 옵션은 다음에서 찾을 수 있습니다.SO에 대한 이 질문.

명령에 -P 옵션을 추가하여 문제를 해결했으므로 다음과 같이 작동합니다.

grep -Pv "^[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+$"

다른 선택지를 지적했다@필리포스주석(4개 이상의 탭이 있는 줄만 일치). 그러나 -P 옵션도 필요합니다.

grep -P '\t.*\t.*\t.*\t'

답변4

다른 사람들이 이미 지적했듯이 \t정규식은 TAB을 나타내지 않습니다. 따라서 확실한 해결책은 문자 그대로 TAB 문자를 추가하는 것입니다. 그러면 BASH가 약간 까다로워질 수 있습니다. 그러나 ^V( Control+) 입력 텍스트 탭 문자를 사용할 수 있습니다 vTAB.

어쩌면 setup TAB='Control+가 더 편리할 수도 있습니다 v TAB'. 또 다른 방법은 +문자 그대로 비확장 정규식(BRE)으로 처리하는 것입니다("기본 정규식과 확장 정규식man grep)이므로 다음을 사용하십시오.

grep -v "^[^$TAB]\+$TAB[^$TAB]\+$TAB[^$TAB]\+$TAB[^$TAB]\+$"

(여기서 변수를 로 단축할 수도 있으며 ( 또는 ) 를 T사용할 필요는 없지만 예상치 못한 상황에 대비하세요)${TAB}${T}

또는 원하는 경우 egrep다음과 같이 반복 그룹을 사용할 수 있습니다.

egrep -v "^([^$TAB]+$TAB){3}[^$TAB]+$"

관련 정보