특정 텍스트가 포함된 열 삭제

특정 텍스트가 포함된 열 삭제

다음과 같은 특정 텍스트가 포함된 열을 삭제하는 옵션을 찾고 있습니다.

"디디"

aaa bbb ccc ddd eee fff
1   2   3   4   5   6
2   3   4   5   6   0

따라서 출력은 다음과 같습니다.

aaa bbb ccc eee fff
1   2   3   5   6
2   3   4   6   0

열 4를 제거하고 동일한 작업을 수행하는 간단한 옵션이 있다는 것을 알고 있지만 내 *.csv 파일은 정렬되지 않습니다. 어떤 아이디어가 있나요?

답변1

sed올바른 도구가 아닙니다. 노력하다 awk:

$ awk -v OFS='\t' 'NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}} {for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS}' file
aaa     bbb     ccc     eee     fff
1       2       3       5       6
2       3       4       6       0

삭제하려는 문자열( ddd 이 예에서는)이 첫 번째 행의 필드로 나타난다고 가정합니다.

어떻게 작동하나요?

  • -v OFS='\t'

    그러면 출력 필드 구분 기호가 탭으로 설정됩니다. 다른 것을 사용하는 경우 이 설정을 변경하세요.

  • NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}}

    그러면 첫 번째 행의 모든 ​​열이 검색됩니다. (마이너스 1)로 열 번호를 ddd변수에 저장합니다 n.

    m마지막 열의 번호로 도 설정되는데 , i마지막 열인 경우 로 설정됩니다 NF-1.

  • for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS

    ddd그러면 첫 번째 줄에 나타나는 필드를 건너뛰고 모든 필드가 인쇄됩니다.

    i+=1i루프를 통과할 때마다 1씩 증가됩니다. 각 루프에서 1 i+=1+(i==n)씩 증가합니다 i. 단, i==n이 경우에는 i2씩 증가합니다. 이는 오른쪽 열을 건너뛰는 효과가 있습니다.

    printf "%s%s",$i,i==m?ORS:OFS마지막 열인지 여부에 따라 i열 구분 기호 OFS또는 행 구분 기호가 뒤에 오는 열을 인쇄합니다 .ORSi

여러 줄

이와 같은 명령을 여러 줄로 작성하는 것을 선호하는 사람들을 위해:

awk -v OFS='\t' '

NR==1{
    for (i=1;i<=NF;i++)
        if ($i=="ddd") {
            n=i-1
            m=NF-(i==NF)
        }
    }

{
    for(i=1;i<=NF;i+=1+(i==n))
        printf "%s%s",$i,i==m?ORS:OFS
}

' file

쉼표로 구분된 파일 사용

입력과 출력을 쉼표로 구분하려면 입력 필드 구분 기호( 사용 -F)와 출력 필드 구분 기호를 변경해야 합니다. 예를 들어 다음 입력 파일을 고려해보세요.

$ cat file2
aaa,bbb,ccc,ddd,eee,fff
1,2,3,4,5,6
2,3,4,5,6,0

그런 다음 다음을 사용하십시오.

$ awk -F, -v OFS=, 'NR==1{for (i=1;i<=NF;i++)if ($i=="ddd"){n=i-1;m=NF-(i==NF)}} {for(i=1;i<=NF;i+=1+(i==n))printf "%s%s",$i,i==m?ORS:OFS}' file2
aaa,bbb,ccc,eee,fff
1,2,3,5,6
2,3,4,6,0

답변2

이것은 (대부분의 경우)에서 가능할 수도 있지만 sed다른 도구를 사용하는 것보다 더 간단할지는 의문입니다. 가장 쉬운 방법은 먼저 원하는 필드 번호를 얻은 다음 파일을 통해 나머지를 인쇄하는 것입니다. 예를 들어 Perl에서는 다음과 같습니다.

$ perl -lane 'if($.==1){for(0..$#F){$d=$_ if $F[$_] eq "ddd"}} 
              print "@F[0..$d-1] @F[$d+1..$#F]"' file
aaa bbb ccc eee fff
1 2 3 5 6
2 3 4 6 0

그러나 이로 인해 형식이 엉망이 됩니다. 중요하다면John1024의 답변 사용대신에.

답변3

#!/bin/bash
read -a header <file                 # read first line into array "header"
for i in ${!header[@]}               # iterate through array indexes
do
    if [ "${header[i]}" = "ddd" ]    # find column equal the pattern
    then
        n=$[++i]                     # put column number in variable "n"
        break
    fi
done
# print all column except found delimited by <TAB>
cut --complement -f ${n} < <(tr -s ' ' '\t' <6)

하지만 원한다면 "그냥sed"(최적은 아니더라도)

sed "s/\S\+\s*//$(sed 's/\s\+/\n/g;1q' file | sed -n '/ddd/=')" file

\S\+\s*- 평균 1개 열(공백이 아닌 문자 뒤에 가능한 공백이 있음).
s/<pattern>//<number>- 교체만 가능숫자처음으로 나타남무늬. - 첫 번째 줄(제목)에서만
s/\s\+/\n/g모든 공백 또는 공백 블록을 ewline으로 바꿉니다 . 따라서 헤더 열을 행으로 변환합니다. - 줄 번호를 출력하세요.\n
1q
sed -n '/ddd/=무늬존재함 == 열 수

답변4

awk -F "\t" -v "Pat=ddd" 'NR == 1 {for( i = 1; i <= NF; i++) Take[ i] = (Pat != $i)} {for ( i = 1; i <= NF; i++) if( Take[ i]) printf $i FS; print ""}' YourFile
  • 제외되지 않은 필드 인쇄
  • 입력과 동일한 구분 기호를 사용하십시오( -F "\t").
  • ( )를 제외하려면 패턴 선택에 변수를 사용하십시오 -v "Pat=ddd". 많은 선택을 하고 싶다면 정규식 선택을 쉽게 수정할 수 있습니다.
  • 혼란을 피하기 위해 2개의 루프로 완료되지만 하나의 루프에서만 수행됩니다.

관련 정보